Example #1
0
        /// <summary>
        /// Renders the tab thumbnail (<paramref name="image" />) using the given dimensions and coordinates and blends it properly with the underlying desktop
        /// elements.
        /// </summary>
        /// <param name="image">Thumbnail to display.</param>
        /// <param name="opacity">Opacity that <paramref name="image" /> should be displayed with.</param>
        /// <param name="width">Width of <paramref name="image" />.</param>
        /// <param name="height">Height of <paramref name="image" />.</param>
        /// <param name="position">Screen position that <paramref name="image" /> should be displayed at.</param>
        public void UpdateWindow(Bitmap image, byte opacity, int width, int height, POINT position)
        {
            IntPtr windowHandle = User32.GetWindowDC(Handle);
            IntPtr deviceContextHandle = Gdi32.CreateCompatibleDC(windowHandle);
            IntPtr bitmapHandle = image.GetHbitmap(Color.FromArgb(0));
            IntPtr oldBitmapHandle = Gdi32.SelectObject(deviceContextHandle, bitmapHandle);
            SIZE size = new SIZE
                        {
                            cx = 0,
                            cy = 0
                        };
            POINT destinationPosition = new POINT
                                        {
                                            x = 0,
                                            y = 0
                                        };

            if (width == -1 || height == -1)
            {
                // No width and height specified, use the size of the image
                size.cx = image.Width;
                size.cy = image.Height;
            }

            else
            {
                // Use whichever size is smallest, so that the image will be clipped if necessary
                size.cx = Math.Min(image.Width, width);
                size.cy = Math.Min(image.Height, height);
            }

            // Set the opacity and blend the image with the underlying desktop elements using User32.UpdateLayeredWindow
            BLENDFUNCTION blendFunction = new BLENDFUNCTION
                                          {
                                              BlendOp = Convert.ToByte((int) AC.AC_SRC_OVER),
                                              SourceConstantAlpha = opacity,
                                              AlphaFormat = Convert.ToByte((int) AC.AC_SRC_ALPHA),
                                              BlendFlags = 0
                                          };

            User32.UpdateLayeredWindow(Handle, windowHandle, ref position, ref size, deviceContextHandle, ref destinationPosition, 0, ref blendFunction, ULW.ULW_ALPHA);

            Gdi32.SelectObject(deviceContextHandle, oldBitmapHandle);
            Gdi32.DeleteObject(bitmapHandle);
            Gdi32.DeleteDC(deviceContextHandle);
            User32.ReleaseDC(Handle, windowHandle);
        }
		/// <summary>
		/// Renders the tabs and then calls <see cref="User32.UpdateLayeredWindow" /> to blend the tab content with the underlying window (
		/// <see cref="_parentForm" />).
		/// </summary>
		/// <param name="cursorPosition">Current position of the cursor.</param>
		/// <param name="forceRedraw">Flag indicating whether a full render should be forced.</param>
		public void Render(Point cursorPosition, bool forceRedraw = false)
		{
			if (!IsDisposed && _parentForm.TabRenderer != null && _parentForm.WindowState != FormWindowState.Minimized && _parentForm.ClientRectangle.Width > 0)
			{
				cursorPosition = GetRelativeCursorPosition(cursorPosition);

				using (Bitmap bitmap = new Bitmap(Width, Height, PixelFormat.Format32bppArgb))
				{
					using (Graphics graphics = Graphics.FromImage(bitmap))
					{
						DrawTitleBarBackground(graphics);

						// Since classic mode themes draw over the *entire* titlebar, not just the area immediately behind the tabs, we have to offset the tabs
						// when rendering in the window
						Point offset = _parentForm.WindowState != FormWindowState.Maximized && DisplayType == DisplayType.Classic
							? new Point(0, SystemInformation.CaptionButtonSize.Height)
							: _parentForm.WindowState != FormWindowState.Maximized
								? new Point(0, SystemInformation.VerticalResizeBorderThickness - SystemInformation.BorderSize.Height)
								: new Point(0, 0);

						// Render the tabs into the bitmap
						_parentForm.TabRenderer.Render(_parentForm.Tabs, graphics, offset, cursorPosition, forceRedraw);

						// Cut out a hole in the background so that the control box on the underlying window can be shown
						if (DisplayType == DisplayType.Classic && (_parentForm.ControlBox || _parentForm.MaximizeBox || _parentForm.MinimizeBox))
						{
							int boxWidth = 0;

							if (_parentForm.ControlBox)
								boxWidth += SystemInformation.CaptionButtonSize.Width;

							if (_parentForm.MinimizeBox)
								boxWidth += SystemInformation.CaptionButtonSize.Width;

							if (_parentForm.MaximizeBox)
								boxWidth += SystemInformation.CaptionButtonSize.Width;

							CompositingMode oldCompositingMode = graphics.CompositingMode;

							graphics.CompositingMode = CompositingMode.SourceCopy;
							graphics.FillRectangle(
								new SolidBrush(Color.Transparent), Width - boxWidth, 0, boxWidth, SystemInformation.CaptionButtonSize.Height);
							graphics.CompositingMode = oldCompositingMode;
						}

						IntPtr screenDc = User32.GetDC(IntPtr.Zero);
						IntPtr memDc = Gdi32.CreateCompatibleDC(screenDc);
						IntPtr oldBitmap = IntPtr.Zero;
						IntPtr bitmapHandle = IntPtr.Zero;

						try
						{
							// Copy the contents of the bitmap into memDc
							bitmapHandle = bitmap.GetHbitmap(Color.FromArgb(0));
							oldBitmap = Gdi32.SelectObject(memDc, bitmapHandle);

							SIZE size = new SIZE
							            {
								            cx = bitmap.Width,
								            cy = bitmap.Height
							            };

							POINT pointSource = new POINT
							                    {
								                    x = 0,
								                    y = 0
							                    };
							POINT topPos = new POINT
							               {
								               x = Left,
								               y = Top
							               };
							BLENDFUNCTION blend = new BLENDFUNCTION
							                      {
								                      // We want to blend the bitmap's content with the screen content under it
								                      BlendOp = Convert.ToByte((int) AC.AC_SRC_OVER),
								                      BlendFlags = 0,
								                      SourceConstantAlpha = 255,
								                      // We use the bitmap's alpha channel for blending instead of a pre-defined transparency key
								                      AlphaFormat = Convert.ToByte((int) AC.AC_SRC_ALPHA)
							                      };

							// Blend the tab content with the underlying content
							if (!User32.UpdateLayeredWindow(
								Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, ULW.ULW_ALPHA))
							{
								int error = Marshal.GetLastWin32Error();
								throw new Win32Exception(error, "Error while calling UpdateLayeredWindow().");
							}
						}

							// Clean up after ourselves
						finally
						{
							User32.ReleaseDC(IntPtr.Zero, screenDc);

							if (bitmapHandle != IntPtr.Zero)
							{
								Gdi32.SelectObject(memDc, oldBitmap);
								Gdi32.DeleteObject(bitmapHandle);
							}

							Gdi32.DeleteDC(memDc);
						}
					}
				}
			}
		}