PageRenderTime 31ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Huddled/Interop/Vista/WindowImage.cs

#
C# | 327 lines | 191 code | 43 blank | 93 comment | 26 complexity | 0c45672276fedbe6fd945d1bc88642f8 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. // Copyright (c) 2008 Joel Bennett http://HuddledMasses.org/
  2. // Permission is hereby granted, free of charge, to any person obtaining a copy
  3. // of this software and associated documentation files (the "Software"), to deal
  4. // in the Software without restriction, including without limitation the rights
  5. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  6. // copies of the Software, and to permit persons to whom the Software is
  7. // furnished to do so, subject to the following conditions:
  8. // The above copyright notice and this permission notice shall be included in
  9. // all copies or substantial portions of the Software.
  10. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  11. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  13. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  14. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  15. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  16. // SOFTWARE.
  17. // *****************************************************************************
  18. // NOTE: YOU MAY *ALSO* DISTRIBUTE THIS FILE UNDER ANY OF THE FOLLOWING...
  19. // PERMISSIVE LICENSES:
  20. // BSD: http://www.opensource.org/licenses/bsd-license.php
  21. // MIT: http://www.opensource.org/licenses/mit-license.html
  22. // Ms-PL: http://www.opensource.org/licenses/ms-pl.html
  23. // RECIPROCAL LICENSES:
  24. // Ms-RL: http://www.opensource.org/licenses/ms-rl.html
  25. // GPL 2: http://www.gnu.org/copyleft/gpl.html
  26. // *****************************************************************************
  27. // LASTLY: THIS IS NOT LICENSED UNDER GPL v3 (although the above are compatible)
  28. using System;
  29. using System.Runtime.InteropServices;
  30. using System.Windows;
  31. using System.Windows.Controls;
  32. using System.Windows.Interop;
  33. using System.Windows.Media;
  34. namespace Huddled.Interop.Vista
  35. {
  36. /// <summary>
  37. /// A DWM Thumbnail packaged as an Image control
  38. /// </summary>
  39. public class ThumbnailImage : Image
  40. {
  41. #region Fields
  42. public static DependencyProperty ClientAreaOnlyProperty = DependencyProperty.Register(
  43. "ClientAreaOnly", // name
  44. typeof(bool), typeof(ThumbnailImage), // Type information
  45. new FrameworkPropertyMetadata(false, // Default Value
  46. FrameworkPropertyMetadataOptions.AffectsRender, // Property Options
  47. new PropertyChangedCallback(OnClientAreaOnlyChanged)) // Change Callback
  48. );
  49. private HwndSource target;
  50. private IntPtr thumb;
  51. public static readonly DependencyProperty WindowSourceProperty = DependencyProperty.Register(
  52. "WindowSource", // name
  53. typeof(IntPtr), typeof(ThumbnailImage), // Type information
  54. new FrameworkPropertyMetadata(IntPtr.Zero, // Default Value
  55. FrameworkPropertyMetadataOptions.AffectsMeasure |
  56. FrameworkPropertyMetadataOptions.AffectsArrange |
  57. FrameworkPropertyMetadataOptions.AffectsRender, // Property Options
  58. new PropertyChangedCallback(OnWindowSourceChanged)) // Change Callback
  59. );
  60. #endregion [rgn]
  61. #region Constructors
  62. /// <summary>Initializes a new instance of the <see cref="ThumbnailImage"/> class.
  63. /// </summary>
  64. public ThumbnailImage(IntPtr source)
  65. : this()
  66. {
  67. WindowSource = source;
  68. InitialiseThumbnail(source);
  69. }
  70. /// <summary>Initializes the <see cref="ThumbnailImage"/> class.
  71. /// </summary>
  72. static ThumbnailImage()
  73. {
  74. OpacityProperty.OverrideMetadata(
  75. typeof(ThumbnailImage),
  76. new FrameworkPropertyMetadata(
  77. 1.0,
  78. FrameworkPropertyMetadataOptions.Inherits,
  79. delegate(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  80. {
  81. ((ThumbnailImage)obj).UpdateThumbnail();
  82. }));
  83. //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
  84. //This style is defined in themes\generic.xaml
  85. DefaultStyleKeyProperty.OverrideMetadata(typeof(ThumbnailImage), new FrameworkPropertyMetadata(typeof(ThumbnailImage)));
  86. }
  87. /// <summary>Initializes a new instance of the <see cref="ThumbnailImage"/> class.
  88. /// </summary>
  89. public ThumbnailImage()
  90. {
  91. // InitializeComponent();
  92. this.LayoutUpdated += new EventHandler(Thumbnail_LayoutUpdated);
  93. this.Unloaded += new RoutedEventHandler(Thumbnail_Unloaded);
  94. ////// hooks for clicks
  95. //this.ClickMode = ClickMode.Press;
  96. //this.MouseDown += new MouseButtonEventHandler(Thumbnail_MouseDown);
  97. //this.MouseUp += new MouseButtonEventHandler(Thumbnail_MouseUp);
  98. //this.MouseLeave += new MouseEventHandler(Thumbnail_MouseLeave);
  99. //keyIsDown = mouseIsDown = false;
  100. }
  101. #endregion [rgn]
  102. #region [rgn] Properties (3)
  103. /// <summary>Gets or sets a value indicating whether to show just the client area instead of the whole Window.
  104. /// </summary>
  105. /// <value><c>true</c> to show just the client area; <c>false</c> to show the whole Window, chrome and all.</value>
  106. public bool ClientAreaOnly
  107. {
  108. get { return (bool)this.GetValue(ClientAreaOnlyProperty); }
  109. set { this.SetValue(ClientAreaOnlyProperty, value); }
  110. }
  111. /// <summary>Gets or sets the opacity factor
  112. /// applied to the entire image when it is rendered in the user interface (UI).
  113. /// This is a dependency property.
  114. /// </summary>
  115. /// <value></value>
  116. /// <returns>The opacity factor. Default opacity is 1.0. Expected values are between 0.0 and 1.0.</returns>
  117. public new double Opacity
  118. {
  119. get { return (double)this.GetValue(OpacityProperty); }
  120. set { this.SetValue(OpacityProperty, value); }
  121. }
  122. /// <summary>Gets or sets the Window source
  123. /// </summary>
  124. /// <value>The Window source.</value>
  125. public IntPtr WindowSource
  126. {
  127. get { return (IntPtr)this.GetValue(WindowSourceProperty); }
  128. set { this.SetValue(WindowSourceProperty, value); }
  129. }
  130. #endregion [rgn]
  131. #region [rgn] Methods (9)
  132. /// <summary>Positions elements and determines a size for the ThumbnailImage
  133. /// </summary>
  134. /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
  135. /// <returns>The actual size used.</returns>
  136. protected override Size ArrangeOverride(Size finalSize)
  137. {
  138. System.Drawing.Size size;
  139. NativeMethods.DwmQueryThumbnailSourceSize(this.thumb, out size);
  140. // scale to fit whatever size we were allocated
  141. double scale = finalSize.Width / size.Width;
  142. scale = Math.Min(scale, finalSize.Height / size.Height);
  143. return new Size(size.Width * scale, size.Height * scale);
  144. }
  145. /// <summary>
  146. /// Measures the size in layout required for child elements and determines a size for the Image.
  147. /// </summary>
  148. /// <param name="availableSize">The available size that this element can give to child elements.
  149. /// Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
  150. /// <returns>
  151. /// The size that this element determines it needs during layout, based on its calculations of child element sizes.
  152. /// </returns>
  153. protected override Size MeasureOverride(Size availableSize)
  154. {
  155. if (IntPtr.Zero == thumb)
  156. {
  157. InitialiseThumbnail(this.WindowSource);
  158. }
  159. System.Drawing.Size size;
  160. NativeMethods.DwmQueryThumbnailSourceSize(thumb, out size);
  161. double scale = 1;
  162. // our preferred size is the thumbnail source size
  163. // if less space is available, we scale appropriately
  164. if (size.Width > availableSize.Width)
  165. scale = availableSize.Width / size.Width;
  166. if (size.Height > availableSize.Height)
  167. scale = Math.Min(scale, availableSize.Height / size.Height);
  168. return new Size(size.Width * scale, size.Height * scale); ;
  169. }
  170. /// <summary>Initialises the thumbnail image
  171. /// </summary>
  172. /// <param name="source">The source.</param>
  173. private void InitialiseThumbnail(IntPtr source)
  174. {
  175. if (IntPtr.Zero != thumb)
  176. { // release the old thumbnail
  177. ReleaseThumbnail();
  178. }
  179. if (IntPtr.Zero != source)
  180. {
  181. // find our parent hwnd
  182. target = (HwndSource)HwndSource.FromVisual(this);
  183. // if we have one, we can attempt to register the thumbnail
  184. if (target != null && 0 == NativeMethods.DwmRegisterThumbnail(target.Handle, source, out this.thumb))
  185. {
  186. NativeMethods.ThumbnailProperties props = new NativeMethods.ThumbnailProperties();
  187. props.Visible = false;
  188. props.ClientAreaOnly = this.ClientAreaOnly;
  189. props.Opacity = (byte)(255 * this.Opacity);
  190. props.Flags = NativeMethods.ThumbnailFlags.Visible | NativeMethods.ThumbnailFlags.SourceClientAreaOnly
  191. | NativeMethods.ThumbnailFlags.Opacity;
  192. NativeMethods.DwmUpdateThumbnailProperties(thumb, ref props);
  193. }
  194. }
  195. }
  196. private static void OnClientAreaOnlyChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
  197. {
  198. if (depObj is ThumbnailImage)
  199. {
  200. if (args.NewValue is bool)
  201. {
  202. (depObj as ThumbnailImage).ClientAreaOnly = (bool)args.NewValue;
  203. //if( !IntPtr.Zero.Equals(WindowSource) )
  204. // InitialiseThumbnail(source);
  205. }
  206. }
  207. }
  208. private static void OnWindowSourceChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
  209. {
  210. if (depObj is ThumbnailImage)
  211. {
  212. if (args.NewValue is IntPtr && !IntPtr.Zero.Equals(args.NewValue))
  213. {
  214. IntPtr source = (IntPtr)args.NewValue;
  215. (depObj as ThumbnailImage).InitialiseThumbnail(source);
  216. }
  217. }
  218. }
  219. /// <summary>Releases the thumbnail
  220. /// </summary>
  221. private void ReleaseThumbnail()
  222. {
  223. if (IntPtr.Zero != thumb)
  224. {
  225. NativeMethods.DwmUnregisterThumbnail(thumb);
  226. this.thumb = IntPtr.Zero;
  227. }
  228. this.target = null;
  229. }
  230. /// <summary>Handles the LayoutUpdated event of the Thumbnail image
  231. /// Actually, we really just ask Windows to paint us at our new size...
  232. /// </summary>
  233. /// <param name="sender">The source of the event.</param>
  234. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  235. private void Thumbnail_LayoutUpdated(object sender, EventArgs e)
  236. {
  237. if (IntPtr.Zero.Equals(thumb))
  238. {
  239. InitialiseThumbnail(this.WindowSource);
  240. }
  241. else if (null != target)
  242. {
  243. if (!target.RootVisual.IsAncestorOf(this))
  244. {
  245. //we are no longer in the visual tree
  246. ReleaseThumbnail();
  247. return;
  248. }
  249. GeneralTransform transform = TransformToAncestor(target.RootVisual);
  250. Point a = transform.Transform(new Point(0, 0));
  251. Point b = transform.Transform(new Point(this.ActualWidth, this.ActualHeight));
  252. NativeMethods.ThumbnailProperties props = new NativeMethods.ThumbnailProperties();
  253. props.Visible = true;
  254. props.Destination = new NativeMethods.ApiRect(
  255. 2 + (int)Math.Ceiling(a.X), 2 + (int)Math.Ceiling(a.Y),
  256. -2 + (int)Math.Ceiling(b.X), -2 + (int)Math.Ceiling(b.Y));
  257. props.Flags = NativeMethods.ThumbnailFlags.Visible | NativeMethods.ThumbnailFlags.RectDestination;
  258. NativeMethods.DwmUpdateThumbnailProperties(thumb, ref props);
  259. }
  260. }
  261. /// <summary>Handles the Unloaded event of the Thumbnail control.
  262. /// </summary>
  263. /// <param name="sender">The source of the event.</param>
  264. /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
  265. private void Thumbnail_Unloaded(object sender, RoutedEventArgs e)
  266. {
  267. ReleaseThumbnail();
  268. }
  269. /// <summary>Updates the thumbnail
  270. /// </summary>
  271. private void UpdateThumbnail()
  272. {
  273. if (IntPtr.Zero != thumb)
  274. {
  275. NativeMethods.ThumbnailProperties props = new NativeMethods.ThumbnailProperties();
  276. props.ClientAreaOnly = this.ClientAreaOnly;
  277. props.Opacity = (byte)(255 * this.Opacity);
  278. props.Flags = NativeMethods.ThumbnailFlags.SourceClientAreaOnly | NativeMethods.ThumbnailFlags.Opacity;
  279. NativeMethods.DwmUpdateThumbnailProperties(thumb, ref props);
  280. }
  281. }
  282. #endregion [rgn]
  283. }
  284. }