[banshee] [NowPlaying] fullscreen video is override-redirect



commit 5caf780696d2e850cc33be0bef6f64c021103cf9
Author: Aaron Bockover <abockover novell com>
Date:   Wed Apr 28 22:38:04 2010 -0400

    [NowPlaying] fullscreen video is override-redirect
    
    This patch brings improvements to fullscreen support on MeeGo/mutter,
    and hopefully helps/works on other window managers. Apologies if it
    doesn't, file bugs, and welcome to git master :)
    
    With that in mind, this patch first makes the video window an
    override-redirect window, so it is unknown to the window manager, and
    cannot be manipulated by it (e.g. moving the video window to another
    workspace in scenarios where the window manager is configured to only
    place one window per workspace).
    
    Next, to cope with what /may/ be a mutter bug, I introduce the ability
    for fullscreen adapters (e.g. the X11/BaconResize adapter) to suggest
    via an event that the Now Playing interface unfullscreen the video
    window.
    
    With the ability to suggest unfullscreening, the X11/BaconResize
    fullscreen adapter (Banshee.NowPlaying.X11.FullscreenAdapter) now
    listens to events from the window manager (via libwnck) and suggests
    that the window be unfullscreened when the active workspace changes.
    This is the part that works around what may be a mutter bug, where video
    appears to be rendered on the new active workspace, even though the
    video window (since it is override-redirect) should still be on the
    previous workspace, where Banshee itself is living.
    
    Finally, since the video window is now override-redirect, and again, the
    window manager doesn't know about it, we have to make the main Banshee
    window be fullscreen whenever the video window goes fullscreen, so that
    the window manager knows there is actually a fullscreen window on the
    workspace and can react appropriately (e.g. by not allowing toolbars or
    other elements to raise above it).
    
    When unfullscreening the video window, the fullscreen state of the main
    window should be restored to whatever it was before going to video
    fullscreen.
    
    Phew.

 .../Banshee.NowPlaying.X11/FullscreenAdapter.cs    |   89 +++++++++++++++++++-
 .../Banshee.NowPlaying/FullscreenAdapter.cs        |   14 +++-
 .../Banshee.NowPlaying/FullscreenWindow.cs         |    4 +-
 .../Banshee.NowPlaying/IFullscreenAdapter.cs       |    3 +-
 .../Banshee.NowPlaying/NowPlayingInterface.cs      |   33 +++++++-
 .../Banshee.NowPlaying/OverlayWindow.cs            |    4 +-
 6 files changed, 141 insertions(+), 6 deletions(-)
---
diff --git a/src/Backends/Banshee.NowPlaying.X11/Banshee.NowPlaying.X11/FullscreenAdapter.cs b/src/Backends/Banshee.NowPlaying.X11/Banshee.NowPlaying.X11/FullscreenAdapter.cs
index a0d6267..fab28c9 100644
--- a/src/Backends/Banshee.NowPlaying.X11/Banshee.NowPlaying.X11/FullscreenAdapter.cs
+++ b/src/Backends/Banshee.NowPlaying.X11/Banshee.NowPlaying.X11/FullscreenAdapter.cs
@@ -4,7 +4,7 @@
 // Author:
 //   Aaron Bockover <abockover novell com>
 //
-// Copyright (C) 2008 Novell, Inc.
+// Copyright 2008-2010  Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -91,9 +91,33 @@ namespace Banshee.NowPlaying.X11
         }
 
         private BaconResize resize;
+        private bool is_fullscreen;
+
+        public event EventHandler SuggestUnfullscreen;
+
+        public FullscreenAdapter ()
+        {
+            try {
+                WnckActiveWorkspaceMonitor.Changed += () => {
+                    if (!is_fullscreen) {
+                        return;
+                    }
+
+                    Hyena.Log.Debug ("WnckScreen::ActiveWorkspaceChanged - raising SuggestUnfullscreen");
+                    var handler = SuggestUnfullscreen;
+                    if (handler != null) {
+                        handler (this, EventArgs.Empty);
+                    }
+                };
+            } catch (Exception e) {
+                Hyena.Log.Exception ("Could not configure libwnck support", e);
+            }
+        }
 
         public void Fullscreen (Window window, bool fullscreen)
         {
+            is_fullscreen = fullscreen;
+
             // Create the Bacon X11 Resizer if we haven't before or the window changes
             if (resize == null || resize.Window != window) {
                 if (resize != null) {
@@ -130,5 +154,68 @@ namespace Banshee.NowPlaying.X11
                 resize = null;
             }
         }
+
+#region WNCK
+
+        public delegate void WnckActiveWorkspaceChangedHandler (object o, WnckActiveWorkspaceChangedArgs args);
+
+        public class WnckActiveWorkspaceChangedArgs : GLib.SignalArgs
+        {
+            public IntPtr PreviousWorkspace {
+                get { return (IntPtr)Args[0]; }
+            }
+        }
+
+        private static class WnckActiveWorkspaceMonitor
+        {
+            private const string WNCK_LIB = "libwnck-1.so.22";
+            private const string GOBJECT_LIB = "libgobject-2.0.so";
+
+            [DllImport (WNCK_LIB)]
+            private static extern IntPtr wnck_screen_get_default ();
+
+            [DllImport (WNCK_LIB)]
+            private static extern void wnck_screen_force_update (IntPtr screen);
+
+            [DllImport (WNCK_LIB)]
+            private static extern IntPtr wnck_screen_get_active_workspace (IntPtr screen);
+
+            private delegate void WnckActiveWorkspaceChangedHandler (IntPtr screen,
+                IntPtr previouslyActiveWorkspace, IntPtr user);
+
+            [DllImport (GOBJECT_LIB)]
+            private static extern ulong g_signal_connect_data (IntPtr instance, string detailed_signal,
+                WnckActiveWorkspaceChangedHandler c_handler, IntPtr user, IntPtr notify_closure, uint connect_flags);
+
+            private static WnckActiveWorkspaceChangedHandler active_workspace_changed_handler;
+
+            static WnckActiveWorkspaceMonitor ()
+            {
+                active_workspace_changed_handler = new WnckActiveWorkspaceChangedHandler (OnActiveWorkspaceChanged);
+                var screen = wnck_screen_get_default ();
+                wnck_screen_force_update (screen);
+                g_signal_connect_data (screen, "active-workspace-changed",
+                    active_workspace_changed_handler, IntPtr.Zero, IntPtr.Zero, 0);
+            }
+
+            public static event System.Action Changed;
+
+            private static void OnActiveWorkspaceChanged (IntPtr screen, IntPtr previouslyActiveWorkspace, IntPtr user)
+            {
+                if (wnck_screen_get_active_workspace (screen) == IntPtr.Zero) {
+                    Hyena.Log.Debug ("wnck_screen_get_active_workspace returned NULL, " +
+                        "wnck_screen_force_update might have failed, " +
+                        "so not raising workspace changed event.");
+                } else {
+                    var handler = Changed;
+                    if (handler != null) {
+                        handler ();
+                    }
+                }
+            }
+        }
+
+#endregion
+
     }
 }
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenAdapter.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenAdapter.cs
index 63c5064..cf638cd 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenAdapter.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenAdapter.cs
@@ -4,7 +4,7 @@
 // Author:
 //   Aaron Bockover <abockover novell com>
 //
-// Copyright (C) 2008 Novell, Inc.
+// Copyright 2008-2010 Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -40,6 +40,8 @@ namespace Banshee.NowPlaying
         private bool probed = false;
         private bool first_fullscreen = false;
 
+        public event EventHandler SuggestUnfullscreen;
+
         public void Fullscreen (Window window, bool fullscreen)
         {
             if (!first_fullscreen && !fullscreen) {
@@ -65,6 +67,7 @@ namespace Banshee.NowPlaying
             foreach (TypeExtensionNode node in AddinManager.GetExtensionNodes ("/Banshee/NowPlaying/FullscreenAdapter")) {
                 try {
                     adapter = (IFullscreenAdapter)node.CreateInstance (typeof (IFullscreenAdapter));
+                    adapter.SuggestUnfullscreen += OnSuggestUnfullscreen;
                     Log.DebugFormat ("Loaded IFullscreenAdapter: {0}", adapter.GetType ().FullName);
                     break;
                 } catch (Exception e) {
@@ -76,6 +79,14 @@ namespace Banshee.NowPlaying
             Fullscreen (window, fullscreen);
         }
 
+        private void OnSuggestUnfullscreen (object o, EventArgs args)
+        {
+            var handler = SuggestUnfullscreen;
+            if (handler != null) {
+                handler (this, EventArgs.Empty);
+            }
+        }
+
         public void Dispose ()
         {
             DisposeAdapter ();
@@ -86,6 +97,7 @@ namespace Banshee.NowPlaying
         {
             if (adapter != null) {
                 try {
+                    adapter.SuggestUnfullscreen -= OnSuggestUnfullscreen;
                     adapter.Dispose ();
                 } catch (Exception e) {
                     Log.Exception ("IFullscreenAdapter failed to dispose", e);
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenWindow.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenWindow.cs
index f735ad6..590f54b 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenWindow.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/FullscreenWindow.cs
@@ -6,7 +6,7 @@
 //   Larry Ewing <lewing novell com>
 //   Gabriel Burt <gburt novell com>
 //
-// Copyright (C) 2008 Novell, Inc.
+// Copyright 2008-2010 Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -134,6 +134,8 @@ namespace Banshee.NowPlaying
 
             base.OnRealized ();
 
+            GdkWindow.OverrideRedirect = true;
+
             Screen.SizeChanged += OnScreenSizeChanged;
         }
 
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IFullscreenAdapter.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IFullscreenAdapter.cs
index d2eaab4..fc30fac 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IFullscreenAdapter.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IFullscreenAdapter.cs
@@ -4,7 +4,7 @@
 // Author:
 //   Aaron Bockover <abockover novell com>
 //
-// Copyright (C) 2008 Novell, Inc.
+// Copyright 2008-2010 Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -33,6 +33,7 @@ namespace Banshee.NowPlaying
 {
     public interface IFullscreenAdapter : IDisposable
     {
+        event EventHandler SuggestUnfullscreen;
         void Fullscreen (Gtk.Window window, bool fullscreen);
     }
 }
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
index 83b58f3..b6ce7cb 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
@@ -4,7 +4,7 @@
 // Author:
 //   Aaron Bockover <abockover novell com>
 //
-// Copyright (C) 2008 Novell, Inc.
+// Copyright 2008-2010 Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -44,6 +44,7 @@ namespace Banshee.NowPlaying
         private NowPlayingSource source;
         private Hyena.Widgets.RoundedFrame frame;
         private Gtk.Window video_window;
+        private Gtk.Window primary_window;
         private FullscreenAdapter fullscreen_adapter;
         private ScreensaverManager screensaver;
         
@@ -52,6 +53,7 @@ namespace Banshee.NowPlaying
         public NowPlayingInterface ()
         {
             GtkElementsService service = ServiceManager.Get<GtkElementsService> ();
+            primary_window = service.PrimaryWindow;
 
             Contents = new NowPlayingContents ();
             Contents.ButtonPressEvent += (o, a) => {
@@ -82,12 +84,15 @@ namespace Banshee.NowPlaying
             PackStart (frame, true, true, 0);
 
             fullscreen_adapter = new FullscreenAdapter ();
+            fullscreen_adapter.SuggestUnfullscreen += OnAdapterSuggestUnfullscreen;
             screensaver = new ScreensaverManager ();
         }
 
         public override void Dispose ()
         {
             base.Dispose ();
+            fullscreen_adapter.SuggestUnfullscreen -= OnAdapterSuggestUnfullscreen;
+            fullscreen_adapter.Dispose ();
             screensaver.Dispose ();
         }
 
@@ -122,6 +127,7 @@ namespace Banshee.NowPlaying
 #region Video Fullscreen Override
 
         private ViewActions.FullscreenHandler previous_fullscreen_handler;
+        private bool primary_window_is_fullscreen;
 
         private void DisableFullscreenAction ()
         {
@@ -142,6 +148,7 @@ namespace Banshee.NowPlaying
             }
 
             previous_fullscreen_handler = service.ViewActions.Fullscreen;
+            primary_window_is_fullscreen = (primary_window.GdkWindow.State & Gdk.WindowState.Fullscreen) != 0;
             service.ViewActions.Fullscreen = FullscreenHandler;
             DisableFullscreenAction ();
         }
@@ -164,9 +171,21 @@ namespace Banshee.NowPlaying
             DisableFullscreenAction ();
         }
 
+        private bool is_fullscreen;
+
         private void FullscreenHandler (bool fullscreen)
         {
+            // Note: Since the video window is override-redirect, we
+            // need to fullscreen the main window, so the window manager
+            // actually knows we are actually doing stuff in fullscreen
+            // here. The original primary window fullscreen state is
+            // stored, so when we can restore it appropriately
+
+            is_fullscreen = fullscreen;
+
             if (fullscreen) {
+                primary_window.Fullscreen ();
+
                 MoveVideoExternal (true);
                 video_window.Show ();
                 fullscreen_adapter.Fullscreen (video_window, true);
@@ -176,6 +195,18 @@ namespace Banshee.NowPlaying
                 screensaver.UnInhibit ();
                 fullscreen_adapter.Fullscreen (video_window, false);
                 video_window.Hide ();
+
+                if (!primary_window_is_fullscreen) {
+                    primary_window.Unfullscreen ();
+                }
+            }
+        }
+
+        private void OnAdapterSuggestUnfullscreen (object o, EventArgs args)
+        {
+            if (is_fullscreen) {
+                Hyena.Log.Debug ("Closing fullscreen at request of the FullscreenAdapter");
+                FullscreenHandler (false);
             }
         }
 
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/OverlayWindow.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/OverlayWindow.cs
index b1bb415..371fde0 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/OverlayWindow.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/OverlayWindow.cs
@@ -5,7 +5,7 @@
 //   Aaron Bockover <abockover novell com>
 //   Larry Ewing <lewing novell com>
 //
-// Copyright (C) 2008 Novell, Inc.
+// Copyright 2008-2010 Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -81,6 +81,8 @@ namespace Banshee.NowPlaying
 
             base.OnRealized ();
 
+            GdkWindow.OverrideRedirect = true;
+
             ShapeWindow ();
             Relocate ();
         }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]