[banshee] Windows: Add Win7 thumbnail toolbar playback buttons (bgo#630730)



commit d6bc9b395a36c069245ac1085ce6603c1f524cdc
Author: Pete Johanson <peter peterjohanson com>
Date:   Fri Sep 24 15:22:12 2010 -0400

    Windows: Add Win7 thumbnail toolbar playback buttons (bgo#630730)
    
    Signed-off-by: Gabriel Burt <gabriel burt gmail com>

 .../Banshee.Windows/Banshee.Windows.addin.xml      |    3 +-
 .../Banshee.Windows/Banshee.Windows.csproj         |   14 ++-
 .../Banshee.Windows/ExtensionsForGtkAction.cs      |   73 +++++++++
 .../GtkWindowThumbnailToolbarManager.cs            |   75 +++++++++
 .../Banshee.Windows/WindowsService.cs              |   83 +++++++++--
 .../Windows7Support/TaskbarInterop.cs              |  151 ++++++++++++++++++
 .../Windows7Support/ThumbnailToolbar.cs            |  130 ++++++++++++++++
 .../Windows7Support/ThumbnailToolbarButton.cs      |  163 ++++++++++++++++++++
 .../Windows7Support/ThumbnailToolbarManager.cs     |  125 +++++++++++++++
 .../Banshee.Windows/media-playback-pause.ico       |  Bin 0 -> 1150 bytes
 .../Banshee.Windows/media-playback-start.ico       |  Bin 0 -> 1150 bytes
 .../Banshee.Windows/media-skip-backward.ico        |  Bin 0 -> 1150 bytes
 .../Banshee.Windows/media-skip-forward.ico         |  Bin 0 -> 1150 bytes
 13 files changed, 801 insertions(+), 16 deletions(-)
---
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows.addin.xml b/src/Backends/Banshee.Windows/Banshee.Windows.addin.xml
index 25b0218..5f4b6f6 100644
--- a/src/Backends/Banshee.Windows/Banshee.Windows.addin.xml
+++ b/src/Backends/Banshee.Windows/Banshee.Windows.addin.xml
@@ -11,6 +11,7 @@
   <Dependencies>
     <Addin id="Banshee.Core" version="1.0"/>
     <Addin id="Banshee.Services" version="1.0"/>
+    <Addin id="Banshee.ThickClient" version="1.0"/>
   </Dependencies>
 
   <Extension path="/Banshee/ServiceManager/Service">
@@ -20,4 +21,4 @@
   <Extension path="/Banshee/Platform/HardwareManager">
     <HardwareManager class="Banshee.Windows.Hardware.HardwareManager" id="Banshee.Windows.HardwareManager"/>
   </Extension>
-</Addin>
\ No newline at end of file
+</Addin>
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows.csproj b/src/Backends/Banshee.Windows/Banshee.Windows.csproj
index 05b68b7..295f3f6 100644
--- a/src/Backends/Banshee.Windows/Banshee.Windows.csproj
+++ b/src/Backends/Banshee.Windows/Banshee.Windows.csproj
@@ -3,7 +3,7 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>8.0.50727</ProductVersion>
+    <ProductVersion>9.0.21022</ProductVersion>
     <ProjectGuid>{9AA07695-3EF9-45CE-849E-A0AB9A1F4006}</ProjectGuid>
     <OutputType>Library</OutputType>
     <UseParentDirectoryAsNamespace>true</UseParentDirectoryAsNamespace>
@@ -77,16 +77,24 @@
     <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
     <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
     <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="System.Drawing" />
     <Reference Include="System.Management" />
     <Reference Include="System.Core">
     </Reference>
+    <Reference Include="System.Windows.Forms" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Banshee.Windows\WindowsService.cs" />
+    <Compile Include="Banshee.Windows\ExtensionsForGtkAction.cs" />
+    <Compile Include="Banshee.Windows\GtkWindowThumbnailToolbarManager.cs" />
     <Compile Include="Banshee.Windows.Hardware\HardwareManager.cs" />
     <Compile Include="Banshee.Windows.Hardware\Device.cs" />
     <Compile Include="Banshee.Windows.Hardware\UsbDevice.cs" />
     <Compile Include="Banshee.Windows.Hardware\Volume.cs" />
+    <Compile Include="Windows7Support\TaskbarInterop.cs" />
+    <Compile Include="Windows7Support\ThumbnailToolbar.cs" />
+    <Compile Include="Windows7Support\ThumbnailToolbarButton.cs" />
+    <Compile Include="Windows7Support\ThumbnailToolbarManager.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Banshee.Windows.addin.xml">
@@ -108,8 +116,6 @@
         </MonoDevelop.Autotools.MakefileInfo>
       </Properties>
     </MonoDevelop>
+    <VisualStudio />
   </ProjectExtensions>
-  <ItemGroup>
-    <Folder Include="Banshee.Windows.Hardware\" />
-  </ItemGroup>
 </Project>
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows/ExtensionsForGtkAction.cs b/src/Backends/Banshee.Windows/Banshee.Windows/ExtensionsForGtkAction.cs
new file mode 100644
index 0000000..d5479f6
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Banshee.Windows/ExtensionsForGtkAction.cs
@@ -0,0 +1,73 @@
+//
+// ExtensionsForGtkAction.cs
+//
+// Authors:
+//   Pete Johanson <peter peterjohanson com>
+//
+// Copyright (C) 2010 Pete Johanson
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Drawing;
+using System.Text.RegularExpressions;
+
+using Gtk;
+using Windows7Support;
+
+namespace Banshee.Windows
+{
+    // TODO: If Gtk# ever supports implementing GtkActivatable interface,
+    //       we could use that for updating the ThumbnailtToolbarButton 'automatically'
+    public static class ExtensionsForGtkAction
+    {
+        static short id = 1;
+
+        public static ThumbnailToolbarButton CreateThumbnailToolbarButton (this Gtk.Action action)
+        {
+            return action.CreateThumbnailToolbarButton (null);
+        }
+
+        public static ThumbnailToolbarButton CreateThumbnailToolbarButton (this Gtk.Action action,
+            Func<Gtk.Action, System.Drawing.Icon> icon_callback)
+        {
+            var button = new ThumbnailToolbarButton (id++) {
+                DismissOnClick = false,
+                Tooltip = action.Label.Replace ("_", ""),
+                Enabled = action.Sensitive,
+                Hidden = !action.Visible,
+                Icon = icon_callback != null ? icon_callback (action) : null
+            };
+
+            button.Clicked += (o, e) => action.Activate ();
+
+            action.AddNotification ("icon-name", (o, args) => button.Icon = icon_callback != null ? icon_callback (action) : null);
+            action.AddNotification ("stock-id", (o, args) => button.Icon = icon_callback != null ? icon_callback (action) : null);
+            action.AddNotification ("tooltip", (o, args) => button.Tooltip = action.Label.Replace ("_", ""));
+            action.AddNotification ("sensitive", (o, args) => button.Enabled = action.Sensitive);
+            action.AddNotification ("visible", (o, args) => button.Hidden = !action.Visible);
+
+            return button;
+        }
+    }
+}
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows/GtkWindowThumbnailToolbarManager.cs b/src/Backends/Banshee.Windows/Banshee.Windows/GtkWindowThumbnailToolbarManager.cs
new file mode 100644
index 0000000..72c7971
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Banshee.Windows/GtkWindowThumbnailToolbarManager.cs
@@ -0,0 +1,75 @@
+//
+// GtkWindowThumbnailToolbarManager.cs
+//
+// Authors:
+//   Pete Johanson <peter peterjohanson com>
+//
+// Copyright (C) 2010 Pete Johanson
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+using Gtk;
+
+using Windows7Support;
+
+namespace Banshee.Windows
+{
+    public static class GtkWindowThumbnailToolbarManager
+    {
+        public static void Register (Window window, Action<ThumbnailToolbar> toolbar_creation_callback)
+        {
+            callback_dict[window] = toolbar_creation_callback;
+
+            if (window.IsRealized) {
+                CreateForWindow (window);
+            } else {
+                window.Realized += OnWindowRealized;
+            }
+        }
+
+        static Dictionary<Window, Action<ThumbnailToolbar>> callback_dict = new Dictionary<Window, Action<ThumbnailToolbar>> ();
+
+        static void OnWindowRealized (object o, EventArgs args)
+        {
+            CreateForWindow ((Window)o);
+        }
+
+        static void CreateForWindow (Window window)
+        {
+            Action<ThumbnailToolbar> cb = null;
+
+            if (!callback_dict.TryGetValue (window, out cb)) {
+                return;
+            }
+
+            ThumbnailToolbarManager.Register (gdk_win32_drawable_get_handle (window.GdkWindow.Handle), cb);
+        }
+
+        [DllImport ("libgdk-win32-2.0-0.dll")]
+        static extern IntPtr gdk_win32_drawable_get_handle (IntPtr drawable);
+    }
+}
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs b/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs
index f18beb7..ecc9684 100644
--- a/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs
+++ b/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs
@@ -3,6 +3,7 @@
 //
 // Authors:
 //   Gabriel Burt <gabriel burt gmail com>
+//   Pete Johanson <peter peterjohanson com>
 //
 // Copyright 2011 Novell, Inc.
 //
@@ -27,29 +28,91 @@
 //
 
 using System;
+using System.Collections.Generic;
+using System.Drawing;
 using System.Linq;
-using System.Collections;
-using Gtk;
-using Mono.Unix;
+using System.Text;
 
 using Banshee.ServiceStack;
 using Banshee.Gui;
-using Hyena.Downloader;
 
-using GLib;
-using System.Management;
+using Windows7Support;
 
 namespace Banshee.Windows
 {
-    public class WindowsService : IExtensionService, IDisposable
+    public class WindowsService : IExtensionService
     {
         bool disposed;
+        GtkElementsService elements_service;
+        InterfaceActionService interface_action_service;
 
-        void IExtensionService.Initialize ()
+        private IList<ThumbnailToolbarButton> buttons;
+
+        bool ServiceStart ()
+        {
+            if (elements_service == null || interface_action_service == null)
+                return false;
+
+            buttons = new List<ThumbnailToolbarButton> () {
+                interface_action_service.PlaybackActions["PreviousAction"].CreateThumbnailToolbarButton (a => new Icon (GetResourceStream ("media-skip-backward.ico"))),
+                interface_action_service.PlaybackActions["PlayPauseAction"].CreateThumbnailToolbarButton (a => a.StockId == Gtk.Stock.MediaPlay ? new Icon (GetResourceStream ("media-playback-start.ico")) : new Icon (GetResourceStream ("media-playback-pause.ico"))),
+                interface_action_service.PlaybackActions["NextAction"].CreateThumbnailToolbarButton (a => new Icon (GetResourceStream ("media-skip-forward.ico"))),
+            };
+
+            ServiceManager.ServiceStarted -= OnServiceStarted;
+
+            GtkWindowThumbnailToolbarManager.Register (elements_service.PrimaryWindow, tb => { tb.Buttons = buttons; });
+
+            return true;
+        }
+
+        System.IO.Stream GetResourceStream (string resource_name)
+        {
+            string name = typeof (WindowsService).Assembly.GetManifestResourceNames ().FirstOrDefault (n => n.EndsWith (resource_name));
+
+            if (String.IsNullOrEmpty (name))
+                throw new ArgumentException (String.Format ("Resource named '{0}' not located", resource_name));
+
+            return typeof (WindowsService).Assembly.GetManifestResourceStream (name);
+        }
+
+        void OnServiceStarted (ServiceStartedArgs args)
+        {
+            if (args.Service is GtkElementsService) {
+                elements_service = (GtkElementsService)args.Service;
+                ServiceStart ();
+            } else if (args.Service is InterfaceActionService) {
+                interface_action_service = (InterfaceActionService)args.Service;
+                ServiceStart ();
+            }
+        }        
+
+        #region IExtensionService Members
+
+        public void Initialize ()
         {
             // TODO check for updates and other cool stuff
+
+            elements_service = ServiceManager.Get<GtkElementsService> ();
+            interface_action_service = ServiceManager.Get<InterfaceActionService> ();
+
+            if (!ServiceStart ()) {
+                ServiceManager.ServiceStarted += OnServiceStarted;
+            }
+        }
+
+        #endregion
+
+        #region IService Members
+
+        public string ServiceName {
+            get { return "WindowsService"; }
         }
 
+        #endregion
+
+        #region IDisposable Members
+
         public void Dispose ()
         {
             if (disposed) {
@@ -59,8 +122,6 @@ namespace Banshee.Windows
             disposed = true;
         }
 
-        string IService.ServiceName {
-            get { return "WindowsService"; }
-        }
+        #endregion
     }
 }
diff --git a/src/Backends/Banshee.Windows/Windows7Support/TaskbarInterop.cs b/src/Backends/Banshee.Windows/Windows7Support/TaskbarInterop.cs
new file mode 100644
index 0000000..68ff35a
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Windows7Support/TaskbarInterop.cs
@@ -0,0 +1,151 @@
+//
+// TaskbarInterop.cs
+//
+// Authors:
+//   Pete Johanson <peter peterjohanson com>
+//
+// Copyright (C) 2010 Pete Johanson
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+
+namespace Windows7Support
+{
+    // See http://msdn.microsoft.com/en-us/library/dd391692(v=VS.85).aspx
+    // for the definition of ITaskbarList3.
+    // The definitions here are used for interop via COM with ITaskbarList3.
+
+    [ComImport, Guid ("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
+    [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+    internal interface ITaskbarList3
+    {
+
+        #region ITaskbarList API
+
+        [PreserveSig]
+        void HrInit ();
+        [PreserveSig]
+        void AddTab (IntPtr hwnd);
+        [PreserveSig]
+        void DeleteTab (IntPtr hwnd);
+        [PreserveSig]
+        void ActivateTab (IntPtr hwnd);
+        [PreserveSig]
+        void SetActiveAlt (IntPtr hwnd);
+
+        #endregion
+
+        #region ITaskbarList2 API
+
+        [PreserveSig]
+        void MarkFullscreenWindow (IntPtr hwnd, [MarshalAs (UnmanagedType.Bool)] bool fFullscreen);
+
+        #endregion
+
+        #region ITaskbarList3 API
+
+        [PreserveSig]
+        void SetProgressState ([In] IntPtr hwnd, [In] TASKBAR_PROGRESS_STATUS flags);
+        [PreserveSig]
+        void SetProgressValue ([In] IntPtr hwnd, [In] ulong ullCompleted, [In] ulong ullTotal);
+
+        [PreserveSig]
+        void RegisterTab (IntPtr hwndTab, IntPtr hwndMDI);
+        [PreserveSig]
+        void UnregisterTab ([In] IntPtr hwndTab);
+        [PreserveSig]
+        void SetTabOrder ([In] IntPtr hwndTab, [In, Optional] IntPtr hwndInsertBefore);
+        [PreserveSig]
+        void SetTabActive ([In] IntPtr hwndTab, [In] IntPtr hwndMDI, [In] uint flags);
+
+        [PreserveSig]
+        int ThumbBarAddButtons ([In] IntPtr hwnd, [In] uint numberOfButtons, [In, MarshalAs (UnmanagedType.LPArray)] THUMBBUTTON[] buttons);
+        [PreserveSig]
+        int ThumbBarUpdateButtons ([In] IntPtr hwnd, [In] uint numberOfButtons, [In, MarshalAs (UnmanagedType.LPArray)] THUMBBUTTON[] buttons);
+        [PreserveSig]
+        int ThumbBarSetImageList ([In] IntPtr hwnd, [In] IntPtr hImageList);
+
+        [PreserveSig]
+        void SetOverlayIcon ([In] IntPtr hwnd, [In] IntPtr hIcon, [In, MarshalAs (UnmanagedType.LPWStr)] string pszDescription);
+
+        [PreserveSig]
+        void SetThumbnailTooltip ([In] IntPtr hwnd, [In, MarshalAs (UnmanagedType.LPWStr)] string pszTip);
+
+        [PreserveSig]
+        void SetThumbnailClip ([In] IntPtr hwnd, [In] IntPtr rect);
+
+        #endregion
+    }
+
+    internal enum THUMBBUTTONMASK
+    {
+        THB_BITMAP = 0x1,
+        THB_ICON = 0x2,
+        THB_TOOLTIP = 0x4,
+        THB_FLAGS = 0x8
+    }
+
+    [Flags]
+    internal enum THUMBBUTTONFLAGS
+    {
+        THBF_ENABLED = 0x00000000,
+        THBF_DISABLED = 0x00000001,
+        THBF_DISMISSONCLICK = 0x00000002,
+        THBF_NOBACKGROUND = 0x00000004,
+        THBF_HIDDEN = 0x00000008,
+        THBF_NONINTERACTIVE = 0x00000010
+    }
+
+    internal enum TASKBAR_PROGRESS_STATUS
+    {
+        NO_PROGRESS = 0x0,
+        INDETERMINATE = 0x1,
+        NORMAL = 0x2,
+        ERROR = 0x4,
+        Paused = 0x8
+    }
+
+    [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Auto)]
+    internal struct THUMBBUTTON
+    {
+        [MarshalAs (UnmanagedType.U4)]
+        public THUMBBUTTONMASK dwMask;
+        public UInt32 uId;
+        public UInt32 iBitmap;
+        public IntPtr hIcon;
+
+        [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 260)]
+        public string szTip;
+        [MarshalAs (UnmanagedType.U4)]
+        public THUMBBUTTONFLAGS dwFlags;
+    }
+
+    internal static class CLSID
+    {
+        public static readonly Guid TaskbarList = new Guid ("56FDF344-FD6D-11d0-958A-006097C9A090");
+    }
+}
diff --git a/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbar.cs b/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbar.cs
new file mode 100644
index 0000000..b02549e
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbar.cs
@@ -0,0 +1,130 @@
+//
+// ThumbnailToolbar.cs
+//
+// Authors:
+//   Pete Johanson <peter peterjohanson com>
+//
+// Copyright (C) 2010 Pete Johanson
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows.Forms;
+
+namespace Windows7Support
+{
+    public class ThumbnailToolbar
+    {
+        public void SetImageList (ImageList list)
+        {
+            image_list = list;
+            taskbar.ThumbBarSetImageList (hwnd, list.Handle);
+        }
+
+        public IList<ThumbnailToolbarButton> Buttons {
+            get { return buttons; }
+            set {
+                if (buttons != null)
+                    throw new InvalidOperationException ("The toolbar buttons can only be set once, due to a Windows limitation");
+
+                if (value == null || value.Count == 0)
+                    return;
+
+                buttons = value;
+
+                foreach (ThumbnailToolbarButton b in buttons)
+                    b.Changed += new EventHandler (OnButtonChanged);
+
+                IEnumerable<THUMBBUTTON> native_buttons = GetNativeButtons ();
+                taskbar.ThumbBarAddButtons (hwnd, (uint)native_buttons.Count (), native_buttons.ToArray ());
+            }
+        }
+
+        ImageList image_list;
+        IList<ThumbnailToolbarButton> buttons;
+        ITaskbarList3 taskbar;
+        IntPtr hwnd;
+
+
+        internal ThumbnailToolbar (IntPtr hwnd)
+        {
+            this.hwnd = hwnd;
+            taskbar = (ITaskbarList3)Activator.CreateInstance (Type.GetTypeFromCLSID (CLSID.TaskbarList));
+            taskbar.HrInit ();
+        }
+
+        void OnButtonChanged (object sender, EventArgs e)
+        {
+            UpdateButtons ();
+        }
+
+        IEnumerable<THUMBBUTTON> GetNativeButtons ()
+        {
+            return buttons.Select (b =>
+            {
+                THUMBBUTTONMASK mask = THUMBBUTTONMASK.THB_FLAGS;
+                THUMBBUTTON native_button = new THUMBBUTTON () { uId = (uint)b.Id, dwFlags = GetFlags (b) };
+                if (b.Icon != null) {
+                    mask |= THUMBBUTTONMASK.THB_ICON;
+                    native_button.hIcon = b.Icon.Handle;
+                }
+
+                if (!String.IsNullOrEmpty (b.Tooltip)) {
+                    mask |= THUMBBUTTONMASK.THB_TOOLTIP;
+                    native_button.szTip = b.Tooltip;
+                }
+
+                // TODO: ImageLIst index support.
+
+                native_button.dwMask = mask;
+
+                return native_button;
+            }).ToList ();
+        }
+
+        void UpdateButtons ()
+        {
+            IEnumerable<THUMBBUTTON> native = GetNativeButtons ();
+
+            taskbar.ThumbBarUpdateButtons (hwnd, (uint)native.Count (), native.ToArray ());
+        }
+
+        THUMBBUTTONFLAGS GetFlags (ThumbnailToolbarButton button)
+        {
+            THUMBBUTTONFLAGS flags = button.Enabled ? THUMBBUTTONFLAGS.THBF_ENABLED : THUMBBUTTONFLAGS.THBF_DISABLED;
+
+            if (button.Hidden)
+                flags |= THUMBBUTTONFLAGS.THBF_HIDDEN;
+            if (button.NonInteractive)
+                flags |= THUMBBUTTONFLAGS.THBF_NONINTERACTIVE;
+            if (button.DismissOnClick)
+                flags |= THUMBBUTTONFLAGS.THBF_DISMISSONCLICK;
+            if (button.NoBackground)
+                flags |= THUMBBUTTONFLAGS.THBF_NOBACKGROUND;
+
+            return flags;
+        }
+
+    }
+}
diff --git a/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbarButton.cs b/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbarButton.cs
new file mode 100644
index 0000000..c468f28
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbarButton.cs
@@ -0,0 +1,163 @@
+//
+// ThumbnailToolbarButton.cs
+//
+// Authors:
+//   Pete Johanson <peter peterjohanson com>
+//
+// Copyright (C) 2010 Pete Johanson
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Drawing;
+using System.Text;
+
+namespace Windows7Support
+{
+    public class ThumbnailToolbarButton
+    {
+        public event EventHandler Clicked;
+        public event EventHandler Changed;
+
+        public Int16 Id { get; private set; }
+
+        int image_index = -1;
+        public int ImageIndex {
+            get { return image_index; }
+            set {
+                if (image_index == value)
+                    return;
+
+                image_index = value;
+
+                FireChanged ();
+            }
+        }
+
+        Icon icon;
+        public Icon Icon {
+            get { return icon; }
+            set {
+                if (icon == value)
+                    return;
+
+                icon = value;
+                FireChanged ();
+            }
+        }
+
+        string tooltip;
+        public string Tooltip {
+            get { return tooltip; }
+            set {
+                if (tooltip == value)
+                    return;
+
+                if (tooltip != null && tooltip.Length > 260)
+                    throw new ArgumentException ("Tooltip cannot be greater than 260 characters long.");
+
+                tooltip = value;
+                FireChanged ();
+            }
+        }
+
+        bool enabled = true;
+        public bool Enabled {
+            get { return enabled; }
+            set {
+                if (enabled == value)
+                    return;
+
+                enabled = value;
+                FireChanged ();
+            }
+        }
+
+        bool dismiss_on_click = true;
+        public bool DismissOnClick {
+            get { return dismiss_on_click; }
+            set {
+                if (dismiss_on_click == value)
+                    return;
+
+                dismiss_on_click = value;
+                FireChanged ();
+            }
+        }
+
+        bool hidden;
+        public bool Hidden {
+            get { return hidden; }
+            set {
+                if (hidden == value)
+                    return;
+
+                hidden = value;
+                FireChanged ();
+            }
+        }
+
+        bool non_interactive;
+        public bool NonInteractive {
+            get { return non_interactive; }
+            set {
+                if (non_interactive == value)
+                    return;
+
+                non_interactive = value;
+                FireChanged ();
+            }
+        }
+
+        bool no_background = false;
+        public bool NoBackground {
+            get { return no_background; }
+            set {
+                if (no_background == value)
+                    return;
+
+                no_background = value;
+                FireChanged ();
+            }
+        }
+
+        public ThumbnailToolbarButton (Int16 id)
+        {
+            Id = id;
+        }
+
+        internal void FireClicked ()
+        {
+            var handler = Clicked;
+            if (handler != null)
+                handler (this, EventArgs.Empty);
+        }
+
+        void FireChanged ()
+        {
+            var handler = Changed;
+            if (handler != null)
+                handler (this, EventArgs.Empty);
+        }
+    }
+}
diff --git a/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbarManager.cs b/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbarManager.cs
new file mode 100644
index 0000000..2ee5c46
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Windows7Support/ThumbnailToolbarManager.cs
@@ -0,0 +1,125 @@
+//
+// ThumbnailToolbarManager.cs
+//
+// Authors:
+//   Pete Johanson <peter peterjohanson com>
+//
+// Copyright (C) 2010 Pete Johanson
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Windows7Support
+{
+    public static class ThumbnailToolbarManager
+    {
+        static ThumbnailToolbarManager ()
+        {
+            toolbar_created_msg = RegisterWindowMessage (TASKBAR_BUTTON_CREATED_MSG);
+        }
+
+
+        public static void Register (IntPtr hwnd, Action<ThumbnailToolbar> toolbar_created_callback)
+        {
+            Win32WinProc proc = new Win32WinProc (WndProc);
+            orig_winproc_dict[hwnd] = new Registration ()
+            {
+                ManagedProc = proc,
+                OrigWinProc = SetWindowLongW (hwnd, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate (proc)),
+                CreationCallback = toolbar_created_callback
+            };
+        }
+
+        static Dictionary<IntPtr, ThumbnailToolbar> toolbars = new Dictionary<IntPtr, ThumbnailToolbar> ();
+        static Dictionary<IntPtr, Registration> orig_winproc_dict = new Dictionary<IntPtr, Registration> ();
+
+        private static IntPtr WndProc (IntPtr hWnd, int Msg, int wParam, int lParam)
+        {
+            Registration reg = null;
+
+            if (!orig_winproc_dict.TryGetValue (hWnd, out reg))
+                return IntPtr.Zero;
+
+            if (Msg == toolbar_created_msg) {
+
+                ThumbnailToolbar tb = new ThumbnailToolbar (hWnd);
+                toolbars[hWnd] = tb;
+                reg.CreationCallback (tb);
+
+            } else if (Msg == WM_COMMAND && HiWord (wParam) == THBN_CLICKED) {
+                int button_id = LoWord (wParam);
+                ThumbnailToolbar tb;
+
+                if (toolbars.TryGetValue (hWnd, out tb)) {
+                    ThumbnailToolbarButton button = tb.Buttons.SingleOrDefault (b => b.Id == button_id);
+                    if (button != null)
+                        button.FireClicked ();
+                }
+            }
+
+            return CallWindowProcW (reg.OrigWinProc, hWnd, Msg, wParam, lParam);
+        }
+
+        static int LoWord (int dw)
+        {
+            return dw & 0xFFFF;
+        }
+
+        static int HiWord (int dw)
+        {
+            return (dw >> 16) & 0xFFFF;
+        }
+
+        class Registration
+        {
+            public Win32WinProc ManagedProc;
+            public IntPtr OrigWinProc;
+            public Action<ThumbnailToolbar> CreationCallback;
+        }
+
+        #region native imports
+
+        static readonly uint toolbar_created_msg;
+
+        const string TASKBAR_BUTTON_CREATED_MSG = "TaskbarButtonCreated";
+        const int GWL_WNDPROC = -4;
+        const int WM_COMMAND = 0x0111;
+        const int THBN_CLICKED = 0x1800;
+
+        private delegate IntPtr Win32WinProc (IntPtr hWnd, int Msg, int wParam, int lParam);
+
+        [DllImport ("user32.dll")]
+        private static extern IntPtr SetWindowLongW (IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
+        [DllImport ("user32.dll")]
+        private static extern IntPtr CallWindowProcW (IntPtr proc, IntPtr hWnd, int Msg, int wParam, int lParam);
+
+        [DllImport ("user32.dll")]
+        private static extern uint RegisterWindowMessage (string lpProcName);
+
+        #endregion
+    }
+}
diff --git a/src/Backends/Banshee.Windows/media-playback-pause.ico b/src/Backends/Banshee.Windows/media-playback-pause.ico
new file mode 100644
index 0000000..cfc371c
Binary files /dev/null and b/src/Backends/Banshee.Windows/media-playback-pause.ico differ
diff --git a/src/Backends/Banshee.Windows/media-playback-start.ico b/src/Backends/Banshee.Windows/media-playback-start.ico
new file mode 100644
index 0000000..06f4c7f
Binary files /dev/null and b/src/Backends/Banshee.Windows/media-playback-start.ico differ
diff --git a/src/Backends/Banshee.Windows/media-skip-backward.ico b/src/Backends/Banshee.Windows/media-skip-backward.ico
new file mode 100644
index 0000000..9743b91
Binary files /dev/null and b/src/Backends/Banshee.Windows/media-skip-backward.ico differ
diff --git a/src/Backends/Banshee.Windows/media-skip-forward.ico b/src/Backends/Banshee.Windows/media-skip-forward.ico
new file mode 100644
index 0000000..afb20eb
Binary files /dev/null and b/src/Backends/Banshee.Windows/media-skip-forward.ico differ



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