{$I DFS.INC}  { Standard defines for all Delphi Free Stuff components }

{------------------------------------------------------------------------------}
{ TdfsGradientForm v2.02                                                       }
{ A form to provide gradient filled caption bars ala Microsoft Office.         }
{ You will notice that some of the initial comment characters are followed by  }
{ a colon, and those sometimes contains some odd looking things that resemble  }
{ HTML codes.  These comments are used by the Time2Help application that I     }
{ used to build the help file.                                                 }
{                                                                              }
{ Copyright 2000, Brad Stowers.  All Rights Reserved.                          }
{                                                                              }
{ Copyright:                                                                   }
{ All Delphi Free Stuff (hereafter "DFS") source code is copyrighted by        }
{ Bradley D. Stowers (hereafter "author"), and shall remain the exclusive      }
{ property of the author.                                                      }
{                                                                              }
{ Distribution Rights:                                                         }
{ You are granted a non-exlusive, royalty-free right to produce and distribute }
{ compiled binary files (executables, DLLs, etc.) that are built with any of   }
{ the DFS source code unless specifically stated otherwise.                    }
{ You are further granted permission to redistribute any of the DFS source     }
{ code in source code form, provided that the original archive as found on the }
{ DFS web site (http://www.delphifreestuff.com) is distributed unmodified. For }
{ example, if you create a descendant of TDFSColorButton, you must include in  }
{ the distribution package the colorbtn.zip file in the exact form that you    }
{ downloaded it from http://www.delphifreestuff.com/mine/files/colorbtn.zip.   }
{                                                                              }
{ Restrictions:                                                                }
{ Without the express written consent of the author, you may not:              }
{   * Distribute modified versions of any DFS source code by itself. You must  }
{     include the original archive as you found it at the DFS site.            }
{   * Sell or lease any portion of DFS source code. You are, of course, free   }
{     to sell any of your own original code that works with, enhances, etc.    }
{     DFS source code.                                                         }
{   * Distribute DFS source code for profit.                                   }
{                                                                              }
{ Warranty:                                                                    }
{ There is absolutely no warranty of any kind whatsoever with any of the DFS   }
{ source code (hereafter "software"). The software is provided to you "AS-IS", }
{ and all risks and losses associated with it's use are assumed by you. In no  }
{ event shall the author of the softare, Bradley D. Stowers, be held           }
{ accountable for any damages or losses that may occur from use or misuse of   }
{ the software.                                                                }
{                                                                              }
{ Support:                                                                     }
{ Support is provided via the DFS Support Forum, which is a web-based message  }
{ system.  You can find it at http://www.delphifreestuff.com/discus/           }
{ All DFS source code is provided free of charge. As such, I can not guarantee }
{ any support whatsoever. While I do try to answer all questions that I        }
{ receive, and address all problems that are reported to me, you must          }
{ understand that I simply can not guarantee that this will always be so.      }
{                                                                              }
{ Clarifications:                                                              }
{ If you need any further information, please feel free to contact me directly.}
{ This agreement can be found online at my site in the "Miscellaneous" section.}
{------------------------------------------------------------------------------}
{ The lateset version of my components are always available on the web at:     }
{   http://www.delphifreestuff.com/                                            }
{ See GradForm.txt for notes, known issues, and revision history.              }
{------------------------------------------------------------------------------}
{ Date last modified:  June 22, 2000                                           }
{------------------------------------------------------------------------------}


{: This unit provides the TdfsGradientForm class, and all supporting elements. }
unit GradForm;

{$IFNDEF DFS_WIN32}
  Error!  This unit is only available for Win32.
{$ENDIF}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Consts;

const
  { This shuts up C++Builder 3 about the redefiniton being different. There
    seems to be no equivalent in C1.  Sorry. }
  {$IFDEF DFS_CPPB_3_UP}
  {$EXTERNALSYM DFS_COMPONENT_VERSION}
  {$ENDIF}
  DFS_COMPONENT_VERSION             = 'TdfsGradientForm v2.02';

  {: The minimum number of colors that can be assigned to the
     <See Property=TdfsGradientForm.GradientColors Text=GradientColors> property.
     Any less than 8 colors doesn't look much like a gradient.
     <Related A=MAX_GRADIENT_COLORS;DEF_GRADIENT_COLORS>
  }
  MIN_GRADIENT_COLORS               = 8;
  {: The maximum number of colors that can be assigned to the
     <See Property=TdfsGradientForm.GradientColors Text=GradientColors> property.
     Any more than 512 colors is not noticeable, and just slows the painting
     down. <Related A=MIN_GRADIENT_COLORS;DEF_GRADIENT_COLORS> }
  MAX_GRADIENT_COLORS               = 512;
  {: The default number of colors for the
     <See Property=TdfsGradientForm.GradientColors Text=GradientColors> property.
     This is a good compromise between speed and appearance.
     <Related A=MAX_GRADIENT_COLORS;MIN_GRADIENT_COLORS>}
  DEF_GRADIENT_COLORS               = 64;
  DEF_CAPTION_TEXT_COLOR            = clWhite;
  DEF_INACTIVE_CAPTION_TEXT_COLOR   = clWhite;
  DEF_GRADIENT_START_COLOR          = clBlack;
  DEF_GRADIENT_STOP_COLOR           = clActiveCaption;
  DEF_GRADIENT_INACTIVE_START_COLOR = clBlack;
  DEF_GRADIENT_INACTIVE_STOP_COLOR  = clInactiveCaption;
  DEF_USE_WIN98_GRADIENT            = FALSE;
  DEF_USE_DITHERING                 = TRUE;

type
  {: For some reason, you can not pass HWND and HDC type parameters from
     C++Builder source code to a Delphi component.  For some reason, C++B wants
     to treat these parameters as "void *" (pointer) types, and you will get
     unresolved external linker errors from Builder if you have methods that
     take HWND and/or HDC parameters in other than the private section.

     I have delcared this type so that it makes the code cleaner below. }

  {$IFDEF DFS_CPPB}
  DFS_HDC = pointer;
  {$ELSE}
  DFS_HDC = HDC;
  {$ENDIF}
  
  {: This enumerated type is used by the
     <See Property=TdfsGradientForm.PaintGradient Text=PaintGradient> property to
     indicate when the caption should be painted as a gradient.<BR>
     <UL>
     <LI>gfpAlways <TAB> The gradient should always be drawn.
     <LI>gfpActive <TAB> Only draw the gradient when the form is active.
     <LI>gfpNever  <TAB> Never draw the gradient.
     </UL>
     <Related A=PaintGradient>}
  TGFPaintWhen = (gfpAlways, gfpActive, gfpNever);
  TGFLogoAlign = (laLeft, laRight);

const
  DEF_PAINT_GRADIENT = gfpAlways;

type
  {: Describes the parameters used by an
     <See Event=TdfsGradientForm.OnCaptionPaint Text=OnCaptionPaint> event handler.
     <BR><BR><B>Sender</B> is the TdfsGradientForm that is being painted.<BR><BR>
     <B>Canvas</B> is the drawing surface that is being painted.  Anything you
     want to appear on the caption must be drawn on this canvas.  This canvas is
     not the actual caption canvas, it is a memory bitmap (non-visible).  This
     prevents flicker as many things are being drawn since the actual visible
     drawing only happens when the entire drawing operation is complete.<BR><BR>
     <B>R</B> is a rectangle that describes the area in which you can draw.
     When the event is first fired, this rectangle will be the entire caption
     less the system icon on the left (if any) and the caption buttons on the
     right (if any).  After performing your drawing operations, this value
     should be modified so that the area you have painted is subtracted out.
     This prevents the gradient from painting over what you have just done.
     <Related A=OnCaptionPaint>}
  TGFOnCaptionPaint = procedure(Sender: TObject; Canvas: TCanvas;
     var R: TRect) of object;

//CE_Desc_Begin(TdfsGradientForm)
{TdfsGradientForm is a descendant of the TForm class that paints it's caption
bar in a gradient fill pattern, like the Microsoft Office applications.
By default, it starts with black and moves gradually to the system defined
caption color, although you can override these values.  Also provided is
an event to allow you to add your own custom painting on the caption bar. }
//CE_Desc_End
  TdfsGradientForm = class(TForm)
  private
    // Internal variables
    Colors: array[0..1, 0..MAX_GRADIENT_COLORS-1] of TColorRef;
//**    CaptionFontHandle: HFONT;
    FGradDefClientProc: TFarProc;
    FGradClientInstance: TFarProc;
    // Property variables
    FCaptionTextColor: TColor;
    FInactiveCaptionTextColor: TColor;
    FGradientStartColor: TColor;
    FGradientStopColor: TColor;
    FGradientInactiveStartColor: TColor;
    FGradientInactiveStopColor: TColor;
    FGradientColors: integer;
    FPaintGradient: TGFPaintWhen;
    FCaptionText: string;
    FOnCaptionPaint: TGFOnCaptionPaint;
    FUsingDefaultGradientStopColor: boolean;
    FUsingDefaultGradientInactiveStopColor: boolean;
    FUseWin98Gradient: boolean;
    FRunningOnWin98: boolean;
    FChangingActivationState: boolean;
    FPaint16Color: boolean;
    FSystemIs16Color: boolean;
    FCaptionFont: TFont;
    FUseSystemCaptionFont: boolean;
    FCreating: boolean;
    FUseDithering: boolean;
    FLogo: TBitmap;
    FLogoAlign: TGFLogoAlign;
    FLogoLayered: Boolean;
    FInactiveLogo: TBitmap;

    // Internal methods
    function IsActiveWindow: boolean;
//**    procedure CreateCaptionFontHandle;
    // Window message handlers
    procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCACTIVATE;
    procedure WMNCPaint(var Msg: TMessage); message WM_NCPAINT;
    procedure WMSysColorChange(var Msg: TWMSysColorChange);
       message WM_SYSCOLORCHANGE;
    procedure WMSize(var Msg: TWMSize); message WM_SIZE;
    procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
    procedure WMSetText(var Msg: TWMSetText); message WM_SETTEXT;
    procedure WMGetText(var Msg: TWMGetText); message WM_GETTEXT;
    procedure WMGetTextLength(var Msg: TWMGetTextLength);
       message WM_GETTEXTLENGTH;
    procedure WMSettingChange(var Msg: TMessage); message WM_SETTINGCHANGE;
    procedure WMNCLButtonDown(var Msg: TWMNCLButtonDown);
       message WM_NCLBUTTONDOWN;
    procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
    procedure WMEnterIdle(var Msg: TWMEnterIdle); message WM_ENTERIDLE;
    procedure WMWindowPosChanging(var Msg: TWMWindowPosChanging);
       message WM_WINDOWPOSCHANGING;
    // MDI Client Window Procedure
    procedure GradClientWndProc(var Message: TMessage);
    function GetInhibitGradient: boolean;
    procedure SetCaptionFont(const Value: TFont);
    // Misc
    function GetSysCaptionLogFont: TLogFont;
    procedure SetUseSystemCaptionFont(const Value: boolean);
  protected
    // Virtual methods useful for descandants
    function GetCaptionRect: TRect; virtual;
    procedure InvalidateCaption;
    function DrawCaption(FormDC: DFS_HDC; Active: boolean): TRect; virtual;
    procedure PaintMenuIcon(DC: DFS_HDC; var R: TRect; Active: boolean); virtual;
    procedure FillRectSolid(DC: DFS_HDC; const R: TRect; Active: boolean;
      ActiveColor, InactiveColor : TColor); virtual;
    procedure FillRectGradient(DC: DFS_HDC; const R: TRect;
       Dithered, Active: boolean); virtual;
    procedure PaintCaptionText(DC: DFS_HDC; R: TRect; Active: boolean); virtual;
    procedure PaintCaptionButtons(DC: DFS_HDC; var Rect: TRect); virtual;
    procedure CalculateColors; virtual;
    // Overriden methods
    procedure Loaded; override;
    procedure CreateWnd; override;
    procedure DestroyWnd; override;
    procedure Activate; override;
    procedure Deactivate; override;
    procedure DoShow; override;
    // Property methods
    procedure SetCaptionTextColor(Color: TColor);
    procedure SetInactiveCaptionTextColor(Color: TColor);
    procedure SetGradientStartColor(Color : TColor);
    procedure SetGradientStopColor(Color : TColor);
    procedure SetGradientInactiveStartColor(Color : TColor);
    procedure SetGradientInactiveStopColor(Color : TColor);
    procedure SetGradientColors(Val: integer);
    procedure SetPaintGradient(Val: TGFPaintWhen);
    procedure SetCaptionText(const Val: string);
    procedure SetUseWin98Gradient(Val: boolean);
    procedure SetUseDithering(Val: boolean);
    procedure SetPaint16Color(const Value: boolean);
    procedure SetLogo(const Value: TBitmap);
    procedure SetLogoAlign(const Value: TGFLogoAlign);
    procedure SetLogoLayered(const Value: Boolean);
    procedure SetInactiveLogo(const Value: TBitmap);
    function GetVersion: string;
    procedure SetVersion(const Val: string);
    // Property storage qualifing methods
    function StoreGradientStopColor: boolean;
    function StoreGradientInactiveStopColor: boolean;
    // Utility methods
    function Win98Check: boolean; virtual;
    procedure UpdateCaptionFont; virtual;
  public
    function GetSystemColorBitDepth: integer;
    { This procedure is used to paint the caption gradient. }
    procedure Draw(Active: boolean); virtual;
    // Overridden methods
    { Create creates and initializes an instance of TdfsGradientForm. }
    constructor Create(AOwner: TComponent); override;
    { Destroy destroys an instance of TdfsGradientForm. }
    destructor Destroy; override;

    property InhibitGradient: boolean
       read GetInhibitGradient;
    property Paint16Color: boolean
       read FPaint16Color
       write SetPaint16Color;
    property SystemIs16Color: boolean
       read FSystemIs16Color;
  published
    // Properties
    property Version: string
       read GetVersion
       write SetVersion
       stored FALSE;
    {: Caption specifies a text string that appears in the caption bar. }
    property Caption: string
       read FCaptionText
       write SetCaptionText
       stored TRUE;
    property CaptionFont: TFont
       read FCaptionFont
       write SetCaptionFont;
    property UseSystemCaptionFont: boolean
       read FUseSystemCaptionFont
       write SetUseSystemCaptionFont;
    {: Determines the number of colors used to paint the gradient pattern.  The
       individual colors are determined by fading the start color into the stop
       color.  The number of times this is done is controled by this property.
       The higher the number of colors, the smoother the gradient will appear.
       However, the more colors that are used, the more complex the painting
       will be.
       <Related A=MAX_GRADIENT_COLORS;MIN_GRADIENT_COLORS;DEF_GRADIENT_COLORS> }
    property GradientColors: integer
       read FGradientColors
       write SetGradientColors
       default DEF_GRADIENT_COLORS;
    {: CaptionTextColor is the color that should be used for the text draw in
       the caption bar.  You may have to adjust this color if you change the
       <See Property=TdfsGradientForm.GradientStartColor Text=GradientStartColor>
       to something other than the default of clBlack.
       <Related A=GradientStartColor;GradientStopColor;Caption>}
    property CaptionTextColor: TColor
       read FCaptionTextColor
       write SetCaptionTextColor
       default DEF_CAPTION_TEXT_COLOR;
    property InactiveCaptionTextColor: TColor
       read FInactiveCaptionTextColor
       write SetInactiveCaptionTextColor
       default DEF_INACTIVE_CAPTION_TEXT_COLOR;
    {: The leftmost gradient color.  This is the color that is used at the
       beginning of the caption (the far left), and is gradually faded into the
       <See Property=TdfsGradientForm.GradientStopColor Text=GradientStopColor>.
       <Related A=GradientStopColor;GradientColors> }
    property GradientStartColor: TColor
       read FGradientStartColor
       write SetGradientStartColor
       default DEF_GRADIENT_START_COLOR;
    {: The rightmost gradient color. This is the color that is used at the
       end of the caption (the far right), and is gradually faded from the
       <See Property=TdfsGradientForm.GradientStartColor Text=GradientStartColor>.
       <Related A=GradientStartColor;GradientColors> }
    property GradientStopColor: TColor
       read FGradientStopColor
       write SetGradientStopColor
       stored StoreGradientStopColor
       default DEF_GRADIENT_STOP_COLOR;
    property GradientInactiveStartColor: TColor
       read FGradientInactiveStartColor
       write SetGradientInactiveStartColor
       default DEF_GRADIENT_INACTIVE_START_COLOR;
    property GradientInactiveStopColor: TColor
       read FGradientInactiveStopColor
       write SetGradientInactiveStopColor
       stored StoreGradientInactiveStopColor
       default DEF_GRADIENT_INACTIVE_STOP_COLOR;
    {: Determines if and when the gradient caption should be painted.
     <UL>
     <LI>gfpAlways <TAB> The gradient should always be drawn.
     <LI>gfpActive <TAB> Only draw the gradient when the form is active.
     <LI>gfpNever  <TAB> Never draw the gradient.
     </UL> }
    property PaintGradient: TGFPaintWhen
       read FPaintGradient
       write SetPaintGradient
       default DEF_PAINT_GRADIENT;
    property UseWin98Gradient: boolean
       read FUseWin98Gradient
       write SetUseWin98Gradient
       default DEF_USE_WIN98_GRADIENT;
    property UseDithering: boolean
       read FUseDithering
       write SetUseDithering
       default DEF_USE_DITHERING;
    property Logo: TBitmap
       read FLogo
       write SetLogo;
    property InactiveLogo: TBitmap
       read FInactiveLogo
       write SetInactiveLogo;
    property LogoAlign: TGFLogoAlign
       read FLogoAlign
       write SetLogoAlign
       default laRight;
    property LogoLayered: Boolean
       read FLogoLayered
       write SetLogoLayered
       default FALSE;
    {: This event is fired after the icon, buttons and gradient are painted,
       but just before the text is painted.  It is not fired if the caption is
       painted but not as a gradient, that is if
       <See TdfsGradientForm.PaintGradient Text=PaintGradient> is gfpNever or
       gfpActive and the form is not active.<BR><BR> <B>Sender</B> is the
       TdfsGradientForm that is being painted.<BR><BR><B>Canvas</B> is the drawing
       surface that is being painted.  Anything you want to appear on the
       caption must be drawn on this canvas.  This canvas is not the actual
       caption canvas, it is a memory bitmap (non-visible).  This prevents
       flicker as many things are being drawn since the actual visible drawing
       only happens when the entire drawing operation is complete.<BR><BR>
       <B>R</B> is a rectangle that describes the area in which you can draw.
       When the event is first fired, this rectangle will be the entire caption
       less the system icon on the left (if any) and the caption buttons on the
       right (if any).  After performing your drawing operations, this value
       should be modified so that the area you have painted is subtracted out.
       This prevents the gradient from painting over what you have just done. }
    property OnCaptionPaint: TGFOnCaptionPaint
       read FOnCaptionPaint
       write FOnCaptionPaint;
  end;
  
implementation

{$R GRADFORM.RES}

// A variant record (known as a union in C) to allow easy access to the
// individual red, // green, and blue values of a TColorRef (RGB) value.
type
  TRGBMap = packed record
    case boolean of
      TRUE:  ( RGBVal: DWORD );
      FALSE: ( Red,
               Green,
               Blue,
               Unused: byte );
  end;


var
  EntrancyFlag: boolean;

{: Create creates and initializes an instance of TdfsGradientForm. Call Create
   to instantiate a TdfsGradientForm at runtime.  After calling the inherited
   constructor, Create initializes the following properties:<BR>
   <UL>
   <LI>UsingDefaultGradientStopColor to TRUE.
   <LI>CaptionTextColor to clWhite.
   <LI>GradientStartColor to clBlack.
   <LI>GradientStopColor to clActiveCaption.
   <LI>GradientColors to <See DEF_GRADIENT_COLORS>.
   <LI>PaintGradient to gpfAlways.
   </UL> }
constructor TdfsGradientForm.Create(AOwner: TComponent);
var
  VerInfo: TOSVersionInfo;
begin
  // We set our new property values first so that they will be valid in the
  // OnCreate event handler.  The inherited Create is what calls that event, so
  // we set up first.

  FLogo := TBitmap.Create;
  FInactiveLogo := TBitmap.Create;
  FLogoLayered := FALSE;
  FLogoAlign := laRight;

  // Are we running under Win98, and should we let it do it for us?
  VerInfo.dwOSVersionInfoSize := SizeOf(VerInfo);
  if GetVersionEx(VerInfo) then
    // this will also catch NT 5.
    FRunningOnWin98 := (VerInfo.dwMajorVersion >= 5) or
       ((VerInfo.dwMajorVersion >= 4) and (VerInfo.dwMinorVersion > 0))
  else
    FRunningOnWin98 := FALSE;

  // Are we running on a 16-color system?
  FSystemIs16Color := GetSystemColorBitDepth = 4;

  // Don't paint 16-color by default
  FPaint16Color := FALSE;

  FUseWin98Gradient := DEF_USE_WIN98_GRADIENT;
  FUseDithering := DEF_USE_DITHERING;
  FUsingDefaultGradientStopColor := TRUE;
  FUsingDefaultGradientInactiveStopColor := TRUE;
  FCaptionTextColor := DEF_CAPTION_TEXT_COLOR;
  FInactiveCaptionTextColor := DEF_INACTIVE_CAPTION_TEXT_COLOR;
  // Set gradient start and stop colors.
  FGradientStartColor := DEF_GRADIENT_START_COLOR;
  FGradientStopColor := DEF_GRADIENT_STOP_COLOR;
  FGradientInactiveStartColor := DEF_GRADIENT_INACTIVE_START_COLOR;
  FGradientInactiveStopColor := DEF_GRADIENT_INACTIVE_STOP_COLOR;
  // Set the number of colors to use to create the gradient fill.
  FGradientColors := DEF_GRADIENT_COLORS;
  // Should we paint the gradient when window is inactive.
  FPaintGradient := DEF_PAINT_GRADIENT;
  FOnCaptionPaint := NIL;
  FChangingActivationState := FALSE;
  // Caption font stuff
  FUseSystemCaptionFont := TRUE;
  FCaptionFont := TFont.Create;
  UpdateCaptionFont;

  // Calculate the colors we need to paint the gradient.
  CalculateColors;
//**  CaptionFontHandle := 0;

//  inherited Create(AOwner);

  CreateNew(AOwner {$IFDEF DFS_CPPB_1}, 1 {$ENDIF});
  if (ClassType <> TdfsGradientForm) and not (csDesigning in ComponentState) then
  begin
    FCreating := TRUE;
    try
      if not InitInheritedComponent(Self, TdfsGradientForm) then
        {$IFDEF DFS_COMPILER_2}
        raise EResNotFound.CreateResFmt(sResNotFound, [ClassName]);
        {$ELSE}
        raise EResNotFound.CreateFmt(sResNotFound, [ClassName]);
        {$ENDIF}
    finally
      FCreating := FALSE;
    end;

    // All versions of Delphi, and C4 and up.
    {$IFDEF DFS_DELPHI}
      {$DEFINE DFS_DO_ONCREATE}
    {$ENDIF}
    {$IFDEF DFS_CPPB_4_UP}
      {$DEFINE DFS_DO_ONCREATE}
    {$ENDIF}
    {$IFDEF DFS_DO_ONCREATE}
    try
      if {$IFDEF DFS_COMPILER_4_UP} OldCreateOrder and {$ENDIF}
         assigned(OnCreate) then
        OnCreate(Self);
    except
      Application.HandleException(Self);
    end;
    {$UNDEF DFS_DO_ONCREATE}
    {$ENDIF}
  end;
end;


{: Destroy destroys an instance of TdfsGradientForm. Do not call Destroy
   directly in an application. Instead, call Free. Free verifies that the
   instance is not already freed, and only then calls Destroy.<BR>
   Destroy is used to free resources allocated in the
   <See Method=TdfsGradientForm.Create Text=Create> constructor. }
destructor TdfsGradientForm.Destroy;
begin
  FLogo.Free;
  FInactiveLogo.Free;
  FCaptionFont.Free;
  // Clean up the font we created.
//**  if CaptionFontHandle <> 0 then
//**    DeleteObject(CaptionFontHandle);
    
  inherited Destroy;
end;


procedure TdfsGradientForm.Loaded;
begin
  inherited Loaded;
  // Create a font for the caption bar.
//**  CreateCaptionFontHandle;
end;


procedure TdfsGradientForm.CreateWnd;
begin
  inherited CreateWnd;
  if (not InhibitGradient) and (FormStyle = fsMDIForm) then
  begin
    FGradClientInstance := MakeObjectInstance(GradClientWndProc);
    FGradDefClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
    SetWindowLong(ClientHandle, GWL_WNDPROC, Longint(FGradClientInstance));
  end else
    FGradClientInstance := NIL;
//**  if not (csLoading in ComponentState) then
    // Create a font for the caption bar.
//**    CreateCaptionFontHandle;
end;

procedure TdfsGradientForm.DestroyWnd;
begin
  if (FormStyle = fsMDIForm) and assigned(FGradClientInstance) then
  begin
    SetWindowLong(ClientHandle, GWL_WNDPROC, Longint(FGradDefClientProc));
    FreeObjectInstance(FGradClientInstance);
  end;

  inherited DestroyWnd;
end;

procedure TdfsGradientForm.SetGradientColors(Val: integer);
begin
  if (Val = FGradientColors) or (Val < MIN_GRADIENT_COLORS) or
     (Val > MAX_GRADIENT_COLORS) then
    exit;

  FGradientColors := Val;
  // The number of colors have changed, we need to recalculate the colors we
  // use to paint.
  CalculateColors;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetCaptionTextColor(Color: TColor);
begin
  if FCaptionTextColor = Color then
    exit;

  FCaptionTextColor := Color;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetInactiveCaptionTextColor(Color: TColor);
begin
  if FInactiveCaptionTextColor = Color then
    exit;

  FInactiveCaptionTextColor := Color;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetGradientStartColor(Color : TColor);
begin
  FGradientStartColor := Color;
  // The colors have changed, we need to recalculate the colors we use to paint.
  CalculateColors;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetGradientStopColor(Color : TColor);
begin
  FGradientStopColor := Color;
  FUsingDefaultGradientStopColor := FGradientStopColor = clActiveCaption;
  // The colors have changed, we need to recalculate the colors we use to paint.
  CalculateColors;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetGradientInactiveStartColor(Color : TColor);
begin
  FGradientInactiveStartColor := Color;
  // The colors have changed, we need to recalculate the colors we use to paint.
  CalculateColors;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetGradientInactiveStopColor(Color : TColor);
begin
  FGradientInactiveStopColor := Color;
  FUsingDefaultGradientInactiveStopColor :=
     (FGradientInactiveStopColor = clInactiveCaption);
  // The colors have changed, we need to recalculate the colors we use to paint.
  CalculateColors;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetPaintGradient(Val: TGFPaintWhen);
begin
  if FPaintGradient = Val then
     exit;

  FPaintGradient := Val;
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetCaptionText(const Val: string);
begin
  if EntrancyFlag then
    exit;

  EntrancyFlag := TRUE;
  try
    // Have to do this so the MDI window menus get updated and application
    // titles get updated (taskbar and Alt-Tab text)
    inherited Caption := Val;

    FCaptionText := Val;
    if (not InhibitGradient) and HandleAllocated and IsWindowVisible(Handle) then
    begin
      if (FormStyle = fsMDIChild) {and FChangingActivationState} then
      begin
        if WindowState = wsMaximized then
          // Need to cause main form's caption to be redrawn, not the MDI child.
          SetWindowPos(Application.MainForm.Handle, 0, 0, 0, 0, 0,
             SWP_DRAWFRAME or SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE
             or SWP_NOZORDER)
        else
          InvalidateCaption;
      end else
        Draw(IsActiveWindow);
    end;

  finally
    EntrancyFlag := FALSE;
  end;
end;

procedure TdfsGradientForm.SetUseWin98Gradient(Val: boolean);
begin
  if Val <> FUseWin98Gradient then
  begin
    FUseWin98Gradient := Val;
    if HandleAllocated then
    begin
      RecreateWnd;
      // hmmm, how to get it to show again in the IDE?
    end;
  end;
end;

procedure TdfsGradientForm.SetUseDithering(Val: boolean);
begin
  if Val <> FUseDithering then
  begin
    FUseDithering := Val;
    InvalidateCaption;
  end;
end;

function TdfsGradientForm.IsActiveWindow: boolean;
begin
  if FormStyle = fsMDIChild then
    if assigned(Application.MainForm) then
      Result := (GetActiveWindow = Application.MainForm.Handle) and
                (TForm(Application.MainForm).ActiveMDIChild = Self)
    else
      Result := FALSE
  else
    Result := GetActiveWindow=Handle;
end;

procedure TdfsGradientForm.CalculateColors;
var
  LoColor, HiColor: TRGBMap;
  RedPct,
  GreenPct,
  BluePct: real;
  x,
  Band: integer;
begin
  // Get colors for both active and inactive captions.
  for x := 0 to 1 do
  begin
    if x = 0 then   // inactive captions
    begin
      LoColor.RGBVal := ColorToRGB(FGradientInactiveStartColor);
      HiColor.RGBVal := ColorToRGB(FGradientInactiveStopColor);
    end else begin    // active caption
      LoColor.RGBVal := ColorToRGB(FGradientStartColor);
      HiColor.RGBVal := ColorToRGB(FGradientStopColor);
    end;
    // Figure out the percentage of each RGB value needed for banding
    RedPct   := (HiColor.Red - LoColor.Red)/ (FGradientColors-1);
    GreenPct := (HiColor.Green - LoColor.Green) / (FGradientColors-1);
    BluePct  := (HiColor.Blue - LoColor.Blue) / (FGradientColors-1);
    // Use the percentage of each color to create each band color.
    for Band := 0 to (FGradientColors-1) do
      Colors[x][Band] := RGB(LoColor.Red + round(RedPct * (Band)),
         LoColor.Green + round(GreenPct * (Band)),
         LoColor.Blue + round(BluePct * (Band)));
  end;
end;

//**
{procedure TdfsGradientForm.CreateCaptionFontHandle;
var
  NCM: TNonClientMetrics;
begin
  if CaptionFontHandle <> 0 then
    DeleteObject(CaptionFontHandle);
  NCM.cbSize := SizeOf(NCM);
  if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NCM, 0) then
  begin
    if BorderStyle in [bsToolWindow, bsSizeToolWin] then
      CaptionFontHandle := CreateFontIndirect(NCM.lfSmCaptionFont)
    else
      CaptionFontHandle := CreateFontIndirect(NCM.lfCaptionFont);
  end else
    CaptionFontHandle := 0;
end;
}

// The caption rect is the rectangle we are interested in painting.  This will
// be the area that contains the caption icon, text and buttons.
function TdfsGradientForm.GetCaptionRect: TRect;
begin
  // Designing mode always draws the form as bsSizeable
  if csDesigning in ComponentState then
  begin
    GetWindowRect(Handle, Result);
    // Convert rect from screen (absolute) to client (0 based) coordinates.
    OffsetRect(Result, -Result.Left, -Result.Top);
    // Shrink rectangle to allow for window border.  We let Windows paint it.
    InflateRect(Result, -GetSystemMetrics(SM_CXSIZEFRAME),
       -GetSystemMetrics(SM_CYSIZEFRAME));
    Result.Bottom := Result.Top + GetSystemMetrics(SM_CYCAPTION) - 1;
  end else begin
    // if we have no border style, then just set the rectange empty.
    if BorderStyle = bsNone then
      SetRectEmpty(Result)
    else begin
      GetWindowRect(Handle, Result);
      // Convert rect from screen (absolute) to client (0 based) coordinates.
      OffsetRect(Result, -Result.Left, -Result.Top);
      // Shrink rectangle to allow for window border.  We let Windows paint it.
      if (WindowState = wsMinimized) or (BorderStyle in [bsToolWindow, bsSingle,
        bsDialog]) then
        InflateRect(Result, -GetSystemMetrics(SM_CXFIXEDFRAME),
          -GetSystemMetrics(SM_CYFIXEDFRAME))
      else if BorderStyle in [bsSizeable, bsSizeToolWin] then
        InflateRect(Result, -GetSystemMetrics(SM_CXSIZEFRAME),
          -GetSystemMetrics(SM_CYSIZEFRAME));

      // Set the appropriate height of caption bar.
      if BorderStyle in [bsToolWindow, bsSizeToolWin] then
        Result.Bottom := Result.Top + GetSystemMetrics(SM_CYSMCAPTION) - 1
      else
        Result.Bottom := Result.Top + GetSystemMetrics(SM_CYCAPTION) - 1;
    end;
  end;
end;

// Paint the icon for the system menu.
procedure TdfsGradientForm.PaintMenuIcon(DC: DFS_HDC; var R: TRect; Active: boolean);
{$IFDEF DFS_COMPILER_2}
const
  LR_COPYFROMRESOURCE = $4000; // Missing from WINDOWS.PAS in Delphi 2!
{$ENDIF}
var
  SmallCopy,
  IconHandle: HIcon;
  Size: integer;
begin
  // Does the form have an icon assigned to it?
  if Icon.Handle <> 0 then
    IconHandle := Icon.Handle
  // If not, does the application have an icon?
  else if Application.Icon.Handle <> 0 then
    IconHandle := Application.Icon.Handle
  // If not, then just use the system defined application icon.
  else
    IconHandle := LoadIcon(0, IDI_APPLICATION);

  Size := GetSystemMetrics(SM_CXSMICON);
  SmallCopy := CopyImage(IconHandle, IMAGE_ICON, Size, Size,
     LR_COPYFROMRESOURCE);
  with R do
    // Let CopyImage() make get us a nice 16x16 version of the icon and we'll
    // paint it.
    DrawIconEx(HDC(DC), Left+1, Top+1, SmallCopy, 0, 0, 0, 0, DI_NORMAL);
  DestroyIcon(SmallCopy);
  Inc(R.Left, Size+1);
end;

// Paint the given rectangle with the system solid color.
procedure TdfsGradientForm.FillRectSolid(DC: DFS_HDC; const R: TRect;
  Active: boolean; ActiveColor, InactiveColor : TColor);
var
  OldBrush,
  Brush: HBrush;
begin
  // Create a brush with the appropriate color\
  if Active then
    Brush := CreateSolidBrush(ColorToRGB(ActiveColor))
  else
    Brush := CreateSolidBrush(ColorToRGB(InactiveColor));
  // Select that brush into the temporary DC.
  OldBrush := SelectObject(HDC(DC), Brush);
  try
    // Fill the rectangle using the selected brush -- PatBlt is faster than
    // FillRect
    with R do
      PatBlt(HDC(DC), Left, Top, Right-Left, Bottom-Top, PATCOPY);
  finally
    // Clean up the brush
    SelectObject(HDC(DC), OldBrush);
    DeleteObject(Brush);
  end;
end;

// Paint the given rectangle with the gradient pattern.
procedure TdfsGradientForm.FillRectGradient(DC: DFS_HDC; const R: TRect;
   Dithered, Active: boolean);
  function MaxInt(I1, I2: integer): integer;
  begin
    if I1 > I2 then
      Result := I1
    else
      Result := I2;
  end;
  function MinInt(I1, I2: integer): integer;
  begin
    if I1 < I2 then
      Result := I1
    else
      Result := I2;
  end;
const
  HorizTileWidth: array[0..1] of Integer = (69, 14);
  HorizTileHeight: array[0..1] of Integer = (30, 28);
  TileResName: array[0..1] of String = ('DFS_DITHGRADMASK1','DFS_DITHGRADMASK2');
var
  OldBmp,
  TmpBmp: HBitmap;
  TmpDC: HDC;
  OldBrush,
  Brush: HBrush;
  Step: real;
  Band: integer;

  Width, Height: Integer;
  StartColor, StopColor: DWORD;
  x, y, i: Integer;
  RStart, GStart, BStart: Integer;
  RDiff, GDiff, BDiff: Integer;
  DitherColors, Index: Integer;
  TileBitmap,
  MaskBitmap,
  OffScreenBitmap: TBitmap;
  FromColor,
  ToColor: TColor;
  PixelsToInsert, PixelsNow: Integer;
  ImageList: TImageList;
begin
  Width := R.Right - R.Left;
  if Width < 1 then exit;
  Height := R.Bottom - R.Top;

  StartColor := 0;
  Index := 0;
  RStart := 0;
  GStart := 0;
  BStart := 0;
  RDiff := 0;
  GDiff := 0;
  BDiff := 0;

  if Dithered then
  begin
    // Dithered style gradient
    if Active then
    begin
      StartColor := ColorToRGB(FGradientStartColor);
      StopColor := ColorToRGB(FGradientStopColor);
    end else begin
      StartColor := ColorToRGB(FGradientInactiveStartColor);
      StopColor := ColorToRGB(FGradientInactiveStopColor);
    end;

    RStart := GetRValue(StartColor);
    GStart := GetGValue(StartColor);
    BStart := GetBValue(StartColor);
    RDiff  := GetRValue(StopColor) - RStart;
    GDiff  := GetGValue(StopColor) - GStart;
    BDiff  := GetBValue(StopColor) - BStart;

    if (Abs(RDiff) + Abs(GDiff) + Abs(BDiff)) / Width < 200.0 / 280.0 then
      Index := 0
    else
      Index := 1;

    // Want dithering, but make sure it will look good.
    if (Width < HorizTileWidth[Index] shl 1) or (GetDeviceCaps(HDC(DC),
       SIZEPALETTE) > 0) then
      Dithered := FALSE; // Low color mode, dithering will look horrible.
  end;

  if Dithered then
  begin
    OffScreenBitmap := TBitmap.Create;
    try
      OffScreenBitmap.Width := Width;
      OffScreenBitmap.Height := Height;

      // if dithering is on, we caluclate the number of colors from the width
      DitherColors := (Width div HorizTileWidth[Index]) + 1;
      if Width mod HorizTileWidth[Index] > 0 then
      // if the width is not the multiple of HorizTileWidth, additional pixels
      // must be inserted between the tiles
        PixelsToInsert := Width - (DitherColors - 1) * HorizTileWidth[Index]
      else
        PixelsToInsert := 0;

      // setting up the temp bitmap and loading the tile mask
      ImageList := TImageList.CreateSize(HorizTileWidth[Index],
         HorizTileHeight[Index]);
      MaskBitmap := TBitmap.Create;
      TileBitmap := TBitmap.Create;
      try
        MaskBitmap.LoadFromResourceName(HInstance, TileResName[Index]);
        TileBitmap.Width := HorizTileWidth[Index];
        TileBitmap.Height := HorizTileHeight[Index];

        x := 0;
        FromColor := StartColor;
        for i := 1 to DitherColors do
        begin
          // calculating the next color
          ToColor := RGB(
             MinInt(MaxInt(RStart + MulDiv(i, RDiff, DitherColors - 1), 0), 255),
             MinInt(MaxInt(GStart + MulDiv(i, GDiff, DitherColors - 1), 0), 255),
             MinInt(MaxInt(BStart + MulDiv(i, BDiff, DitherColors - 1), 0), 255));
          // colorizing the tile mask
          TileBitmap.Canvas.Brush.Color := FromColor;
          PatBlt(TileBitmap.Canvas.Handle, 0, 0, HorizTileWidth[Index],
             HorizTileHeight[Index], PATCOPY);
          if ImageList.Count = 0 then
            ImageList.Add(TileBitmap, MaskBitmap)
          else
            ImageList.Replace(0, TileBitmap, MaskBitmap);
          with OffScreenBitmap do
          begin
            // painting the tile mask
            Canvas.Brush.Color := ToColor;
            PatBlt(Canvas.Handle, x, 0, x + HorizTileWidth[Index], Height,
               PATCOPY);

            y := 0;
            while y < Height do
            begin
              ImageList.Draw(Canvas, x, y, 0);
              Inc(y, HorizTileHeight[Index]);
            end;

            Inc(x, HorizTileWidth[Index]);
            // inserting the extra pixels if necessary
            if PixelsToInsert <> 0 then
            begin
              PixelsNow := PixelsToInsert div (DitherColors - 2);
              if i < PixelsToInsert mod (DitherColors - 2) then
                Inc(PixelsNow);
              PatBlt(Canvas.Handle, x, 0, x + PixelsNow, Height, PATCOPY);
              Inc(x, PixelsNow);
            end;
          end;
          FromColor := ToColor;
        end;
      finally
        TileBitmap.Free;
        MaskBitmap.Free;
        ImageList.Free;
      end;

      BitBlt(HDC(DC), R.Left, R.Top, Width, Height,
         OffScreenBitmap.Canvas.Handle, 0, 0, SRCCOPY);
    finally
      OffScreenBitmap.Free;
    end;

  end else begin
    // "Banded" style gradient

    // This may look backwards, but it's not.  If the device capabilities
    // indicate that there are palette entries (more than 0), then we are in
    // a low color mode.  This is because when in high color mode or above,
    // Windows doesn't use palettes; each pixel knows it's RGB value.
    if (GetDeviceCaps(HDC(DC), SIZEPALETTE) > 0) or 
       (Width < GradientColors) then
    begin
      // Low color gradient, slower

      // Determine how large each band should be in order to cover the
      // rectangle (one band for every color intensity level).
      Step := Width / FGradientColors;

      // Start filling bands
      for Band := 0 to (FGradientColors-1) do
      begin
        // Create a brush with the appropriate color for this band
        Brush := CreateSolidBrush(Colors[ord(Active)][Band]);
        // Select that brush into the temporary DC.
        OldBrush := SelectObject(HDC(DC), Brush);
        try
          // Fill the rectangle using the selected brush -- PatBlt is faster
          // than FillRect
          PatBlt(HDC(DC), round(Band*Step) + R.Left, 0,
             round((Band+1)*Step) - round(Band*Step), Height, PATCOPY);
        finally
          // Clean up the brush
          SelectObject(HDC(DC), OldBrush);
          DeleteObject(Brush);
        end;
      end; // for
    end else begin
      // High color gradient, faster
      TmpDC := CreateCompatibleDC(HDC(DC));
      TmpBmp := CreateCompatibleBitmap(HDC(DC), FGradientColors, 1);
      OldBmp := SelectObject(TmpDC, TmpBmp);
      try
        // Start filling bands
        for Band := 0 to (FGradientColors-1) do
          SetPixel(TmpDC, Band, 0, Colors[ord(Active)][Band]);
        StretchBlt(HDC(DC), R.Left, 0, Width, Height, TmpDC, 0, 0,
           FGradientColors-1, 1, SRCCOPY);
      finally
        SelectObject(TmpDC, OldBmp);
        DeleteObject(TmpBmp);
        DeleteDC(TmpDC);
      end;
    end;
  end;
end;

procedure TdfsGradientForm.PaintCaptionText(DC: DFS_HDC; R: TRect; Active: boolean);
var
  OldColor: TColorRef;
  OldMode: integer;
  OldFont: HFont;
  CaptionText: string;
begin
  CaptionText := Caption;
  // Have to turn off complete boolean eval for this "if" statement.  I never
  // have it on anyway, but some do.
  {$IFOPT B+} {$DEFINE DFS_RESET_BOOL_EVAL} {$B-} {$ENDIF}
  if ((FormStyle = fsMDIForm) and (ActiveMDIChild <> NIL) and
      (ActiveMDIChild.WindowState = wsMaximized)) then
    CaptionText := CaptionText + ' - [' + ActiveMDIChild.Caption + ']';
  {$IFDEF DFS_RESET_BOOL_EVAL} {$B+} {$UNDEF DFS_RESET_BOOL_EVAL} {$ENDIF}

  Inc(R.Left, 2);

  // Set the color to paint the text with.
  if Active then
    OldColor := SetTextColor(HDC(DC), ColorToRGB(FCaptionTextColor))
  else
    OldColor := SetTextColor(HDC(DC), ColorToRGB(FInactiveCaptionTextColor));
  // Set the background text painting mode to transparent so that drawing text
  // doesn't distrub the gradient we just painted.  If you didn't do this, then
  // drawing text would also fill the text rectangle with a solid background
  // color, screwing up our gradient.
  OldMode := SetBkMode(HDC(DC), TRANSPARENT);
  // Select in the system defined caption font (see Create constructor).
  if FCaptionFont.Handle <> 0 then
//**  if CaptionFontHandle <> 0 then
    OldFont := SelectObject(HDC(DC), FCaptionFont.Handle)
//**    OldFont := SelectObject(HDC(DC), CaptionFontHandle)
  else
    OldFont := 0;
  try
    // Draw the text making it left aligned, centered vertically, allowing no
    // line breaks.
    DrawText(HDC(DC), PChar(CaptionText), -1, R, DT_LEFT or DT_VCENTER or
       DT_SINGLELINE or DT_END_ELLIPSIS);
  finally
    // Clean up all the drawing objects.
    if OldFont <> 0 then
      SelectObject(HDC(DC), OldFont);
    SetBkMode(HDC(DC), OldMode);
    SetTextColor(HDC(DC), OldColor);
  end;
end;

// Paint the min/max/help/close buttons.
procedure TdfsGradientForm.PaintCaptionButtons(DC: DFS_HDC; var Rect: TRect);
var
  BtnWidth: integer;
  Flag: UINT;
  SrcRect: TRect;
  ABorderStyle: TFormBorderStyle;
  ABorderIcons: TBorderIcons;
begin
  SrcRect := Rect;
  InflateRect(SrcRect, -2, -2);
  if csDesigning in ComponentState then
  begin
    // While designing, the min/max buttons are always shown in a sizeable frame
    ABorderStyle := bsSizeable;
    ABorderIcons := [biSystemMenu, biMinimize, biMaximize];
  end else begin
    ABorderStyle := BorderStyle;
    ABorderIcons := BorderIcons;
  end;

  if ABorderStyle in [bsToolWindow, bsSizeToolWin] then
  begin
    // Tool windows only have the close button, nothing else.
    with SrcRect do
      Left := Right - (GetSystemMetrics(SM_CXSMSIZE)) + 2;
    Flag := DFCS_CAPTIONCLOSE;
    if (GetClassLong(Handle, GCL_STYLE) and CS_NOCLOSE) <> 0 then
      Flag := Flag or DFCS_INACTIVE;
    DrawFrameControl(HDC(DC), SrcRect, DFC_CAPTION, Flag);
    Rect.Right := SrcRect.Left-5;
  end else begin
    BtnWidth := GetSystemMetrics(SM_CXSMICON)-2;
    { Windows is loopy.  It always returns an even number, no matter what }
    if (Odd(BtnWidth) XOR Odd(Rect.Bottom-Rect.Top)) then
      inc(BtnWidth);
    SrcRect.Left := SrcRect.Right - BtnWidth - 2;
    // if it has system menu, it has a close button.
    if biSystemMenu in ABorderIcons then
    begin
      Flag := DFCS_CAPTIONCLOSE;
      if (GetClassLong(Handle, GCL_STYLE) and CS_NOCLOSE) <> 0 then
        Flag := Flag or DFCS_INACTIVE;
      DrawFrameControl(HDC(DC), SrcRect, DFC_CAPTION, Flag);
      OffsetRect(SrcRect, -BtnWidth-4, 0);
      Dec(Rect.Right,BtnWidth+4);
    end;
    // Minimize and Maximized don't show up at all if BorderStyle is bsDialog or
    // if neither of them are enabled.
    if (ABorderStyle in [bsSizeable, bsSingle]) and
       (ABorderIcons * [biMinimize, biMaximize] <> []) then
    begin
      if WindowState = wsMaximized then
        Flag := DFCS_CAPTIONRESTORE
      else
        Flag := DFCS_CAPTIONMAX;
      // if it doesn't have max in style, then it shows up disabled.
      if not (biMaximize in ABorderIcons) then
        Flag := Flag or DFCS_INACTIVE;

      DrawFrameControl(HDC(DC), SrcRect, DFC_CAPTION, Flag);
      OffsetRect(SrcRect, -BtnWidth-2, 0);
      Dec(Rect.Right,BtnWidth+2);

      if WindowState = wsMinimized then
        Flag := DFCS_CAPTIONRESTORE
      else
        Flag := DFCS_CAPTIONMIN;
      // if it doesn't have min in style, then it shows up disabled.
      if not (biMinimize in ABorderIcons) then
        Flag := Flag or DFCS_INACTIVE;

      DrawFrameControl(HDC(DC), SrcRect, DFC_CAPTION, Flag);
      OffsetRect(SrcRect, -BtnWidth-2, 0);
      Dec(Rect.Right,BtnWidth+2);
    end;

    // Help only shows up in bsDialog style, and bsSizeable, bsSingle when there
    // is no min or max button.
    if biHelp in ABorderIcons then
    begin
      if ((ABorderStyle in [bsSizeable, bsSingle]) and
         (ABorderIcons * [biMinimize, biMaximize] = [])) or
         (ABorderStyle = bsDialog) then
      begin
        DrawFrameControl(HDC(DC), SrcRect, DFC_CAPTION, DFCS_CAPTIONHELP);
        Dec(Rect.Right,BtnWidth+2);
      end;
    end;

    Dec(Rect.Right, 3);
  end;
end;


function TdfsGradientForm.DrawCaption(FormDC: DFS_HDC; Active: boolean): TRect;
var
  R: TRect;
  OldBmp,
  Bmp: HBitmap;
  BmpDC: HDC;
  BmpCanvas: TCanvas;
  w,h:integer;
  IsLogoGradient : Boolean;
  GradientRect, LogoRect : TRect;
  LogoWidth : Integer;
  CurrentLogo : TBitmap;
begin
  // Get only the portion we need to draw.
  R := GetCaptionRect;
  Result := R;

  // Convert to logical (0-based) coordinates
  OffsetRect(R, -R.Left, -R.Top);

  W := R.Right - R.Left;
  H := R.Bottom - R.Top;

  // Create a temporary device context to draw on.  Drawing on a temporary DC
  // and copying it to the real DC accomplishes two things:
  // 1) It is faster because Windows doesn't have to draw anything in the
  //    temporary DC on the screen, it only draws when you paint something on a
  //    real DC.  Then it just draws everything at once when we copy it, instead
  //    of drawing a little, do some calculations, draw a little, etc.
  // 2) It looks much better because it is drawn faster.  It reduces the
  //    "flicker" that you would see from each individual part being drawn,
  //    especially the gradient bands.
  BmpDC := CreateCompatibleDC(HDC(FormDC));
  Bmp := CreateCompatibleBitmap(HDC(FormDC), W, H);
  OldBmp := SelectObject(BmpDC, Bmp);

  try
    // If there's a logo bitmap, we need a solid background
    // behind the menu icon, the caption buttons, and the
    // logo; so we need to delay drawing of the gradient
    // until after the menu and buttons are painted.
    IsLogoGradient := FALSE;

    if (FPaintGradient = gfpAlways) or
       (Active and (FPaintGradient = gfpActive)) then
    begin
      if (Assigned (FLogo)) and (not FLogo.Empty) then
      begin
        IsLogoGradient := TRUE;
        FillRectSolid(DFS_HDC (BmpDC), R, Active, GradientStartColor,
          GradientInactiveStartColor);
      end
      else
        // Draw the gradient background in the temporary DC
        FillRectGradient(DFS_HDC(BmpDC), R, UseDithering, Active)
    end
    else
      FillRectSolid(DFS_HDC(BmpDC), R, Active, GetSysColor(COLOR_ACTIVECAPTION),
        GetSysColor(COLOR_INACTIVECAPTION));

    Inc(R.Left, 1);
    // Do we need to paint an icon for the system menu?
    if not ((FormStyle = fsMDIChild) and (WindowState = wsMaximized)) then
    begin
      if IsLogoGradient then
      begin
        // Start by drawing the solid-color end of the bar.
        // There's a solid color under the menu icon if the
        // logo is left-aligned, or under the caption buttons
        // if the logo is right-aligned.
        if LogoAlign = laLeft then
        begin
          if ((biSystemMenu in BorderIcons) and
             (BorderStyle in [bsSingle, bsSizeable])) or
             (csDesigning in ComponentState) then
          begin
            FillRectSolid(DFS_HDC (BmpDC), R, Active, GradientStartColor,
              GradientInactiveStartColor);
            // PaintMenuIcon will adjust the rect so that future drawing operations
            // happen in the right spot.
            PaintMenuIcon(DFS_HDC(BmpDC), R, Active);
          end;
        end
        else  // LogoAlign = laRight
        begin
          FillRectSolid(DFS_HDC(BmpDC), R, Active, GradientStopColor,
            GradientInactiveStopColor);
          PaintCaptionButtons(DFS_HDC(BmpDC), R);
        end;

        if (not Active) and (not FInactiveLogo.Empty) then
          CurrentLogo := FInactiveLogo
        else
          CurrentLogo := FLogo;

        LogoWidth := CurrentLogo.Width;

        if LogoAlign = laLeft then
          LogoRect := Rect(R.Left, R.Top, R.Left + LogoWidth, R.Bottom)
        else
          LogoRect := Rect(R.Right - LogoWidth, R.Top, R.Right, R.Bottom);

        // Make sure LogoRect doesn't fall off the edge
        // of our drawable area (between icon and buttons)
        IntersectRect (LogoRect, LogoRect, R);

        if LogoAlign = laLeft then
          GradientRect := Rect(LogoRect.Right, R.Top, R.Right, R.Bottom)
        else
          GradientRect := Rect(R.Left, R.Top, LogoRect.Left, R.Bottom);

        if GradientRect.Right > GradientRect.Left then
          FillRectGradient(DFS_HDC(BmpDC), GradientRect, UseDithering, Active);

        BitBlt(BmpDC, LogoRect.Left, (LogoRect.Bottom - LogoRect.Top -
          CurrentLogo.Height) div 2 + LogoRect.Top, LogoRect.Right -
          LogoRect.Left, CurrentLogo.Height, CurrentLogo.Canvas.Handle, 0, 0,
          SRCCOPY);

        // Now draw the caption stuff that needs a gradient:
        // caption buttons if logo is left-aligned, or icon
        // if logo is right-aligned.
        if LogoAlign <> laLeft then
        begin
          if ((biSystemMenu in BorderIcons) and
             (BorderStyle in [bsSingle, bsSizeable])) or
             (csDesigning in ComponentState) then
          // PaintMenuIcon will adjust the rect so that future drawing operations
          // happen in the right spot.
          PaintMenuIcon(DFS_HDC(BmpDC), R, Active);
        end
        else  // LogoAlign = laRight
          PaintCaptionButtons(DFS_HDC(BmpDC), R);

        if not LogoLayered then
          IntersectRect(R, R, GradientRect);

        // Done drawing the gradient, icon, caption buttons, and logo.
      end
      else
      begin
        if ((biSystemMenu in BorderIcons) and
           (BorderStyle in [bsSingle, bsSizeable])) or
           (csDesigning in ComponentState) then
          // PaintMenuIcon will adjust the rect so that future drawing operations
          // happen in the right spot.
          PaintMenuIcon(DFS_HDC(BmpDC), R, Active);

        PaintCaptionButtons(DFS_HDC(BmpDC), R); // Paint the min/max/help/close buttons.
      end;
    end;
    if assigned(FOnCaptionPaint) then
    begin
      BmpCanvas := TCanvas.Create;
      try
        BmpCanvas.Handle := BmpDC;
//        BmpCanvas.Font.handle := FCaptionFont.handle;
        BmpCanvas.Font := FCaptionFont;

        FOnCaptionPaint(Self, BmpCanvas, R);
      finally
        BmpCanvas.Free;
      end;
    end;
    PaintCaptionText(DFS_HDC(BmpDC), R, Active); // Paint the caption text.
    // Copy the gradient caption bar to the real DC.
    BitBlt(HDC(FormDC), Result.Left, Result.Top, W, H, BmpDC, 0, 0, SRCCOPY);
  finally
    // Clean up all the temporary drawing objects.
    SelectObject(BmpDC, OldBmp);
    DeleteObject(Bmp);
    DeleteDC(BmpDC);
  end;
end;

// Windows sends this message when the window has been activated or deactivated.
procedure TdfsGradientForm.WMNCActivate(var Msg: TWMNCActivate);
begin
  if not InhibitGradient then
  begin
    Msg.Result := 1;
    // I can't remember what the "bad things" were, and I can't find any problems
    // now if I don't call it.... If some new bug shows up, this is the first
    // place to look. 
{    if FormStyle in [fsMDIForm, fsMDIChild] then
      inherited; { Call inherited or bad things will happen with MDI }
    Draw(Msg.Active);
  end else
    inherited;
end;

// Windows sends this message whenever any part of the non-client area
// (caption, window border) needs repainting.
procedure TdfsGradientForm.WMNCPaint(var Msg: TMessage);
var
{$IFDEF DFS_COMPILER_4_UP}
  SaveWR, CR,
{$ENDIF}
  WR, R: TRect;
  DC: HDC;
  MyRgn: HRGN;
  DeleteRgn: boolean;
begin
  if not InhibitGradient then
  begin
    DeleteRgn := FALSE;
    // The region that needs painting is passed in WParam.  A region is a Windows
    // object used to describe the non-rectangular area used by a combination of
    // rectangles.  We have to typecast it because in Delphi 4 wParam is signed
    // and HRGN in unsigned.  It worked prior to D4 because they were both
    // signed.
    MyRgn := HRGN(Msg.wParam);
    DC := GetWindowDC(Handle);
    try
      GetWindowRect(Handle, WR);
      // Select the update region as the clipping region.  Clipping regions
      // guarantee that any painting done outside of the selected region is not
      // shown (thrown away).
      if SelectClipRgn(DC, MyRgn) = ERROR then
      begin
        // We got passed an invalid region.  Generally, this happens when the
        // window is first created or a MDI is minimized.  We'll create our own
        // region (the rectangle that makes up the entire window) and use that
        // instead.
        with WR do
          MyRgn := CreateRectRgn(Left, Top, Right, Bottom);
        SelectClipRgn(DC, MyRgn);
        DeleteRgn := TRUE;
      end;
      // Convert the clipping region coordinates from screen to client.
      OffsetClipRgn(DC, -WR.Left, -WR.Top);
      // Draw our gradient caption.
      R := DrawCaption(DFS_HDC(DC), IsActiveWindow);
      // Here's the trick.  DrawCaption returns the rectangle that we painted.
      // We now exclude that rectangle from the clipping region.  This guarantees
      // that any further painting that occurs will not happen in this rectangle.
      // That means that when we let the default painting for WM_NCPAINT occur,
      // it will not paint over our gradient. It only paints the stuff that we
      // didn't, like the window borders.
      ExcludeClipRect(DC, R.Left, R.Top, R.Right, R.Bottom);

{$IFDEF DFS_COMPILER_4_UP}
      // Draw border if needed
      if BorderWidth > 0 then
      begin
        Windows.GetClientRect(Handle, CR);
        SaveWR := WR;
        MapWindowPoints(0, Handle, WR, 2);
        OffsetRect(CR, -WR.Left, -WR.Top);
        { Draw borders in non-client area }
        InflateRect(CR, BorderWidth, BorderWidth);
        WR := SaveWR;
        OffsetRect(WR, -WR.Left, -WR.Top);
        Windows.FillRect(DC, WR, Brush.Handle);
        WR := SaveWR;
      end;
{$ENDIF}

      // Convert coordinates back into screen-based.
      OffsetClipRgn(DC, WR.Left, WR.Top);
      // Get the region that is now described by the clipping region.
      GetClipRgn(DC, MyRgn);
      // Pass that region on to the default WM_NCPAINT handler.  Remember, we
      // excluded the rectangle that we painted, so Windows will not be able to
      // paint over what we did. Most gradient captions components just let
      // windows draw its stuff first, and then paint the gradient.  This results
      // in an irritating "flicker", caused by the area being painted normally,
      // and then painted over a second time by the gradient. We have to
      // typecast the wParam parameter because in Delphi 4 wParam is signed and
      // HRGN in unsigned.  It worked prior to D4 because they were both signed.
      Msg.Result := DefWindowProc(Handle, Msg.Msg, WPARAM(MyRgn), Msg.lParam);
    finally
      // If we had to create our own region, we have to clean it up.
      if DeleteRgn then
        DeleteObject(MyRgn);
      ReleaseDC(Handle, DC); // NEVER leave this hanging.
    end;
  end else
    inherited;
end;

// Windows sends this message if the user changes any of the system colors.
procedure TdfsGradientForm.WMSysColorChange(var Msg: TWMSysColorChange);
var
  x: integer;
begin
  // Did they change to 16-color mode?
  FSystemIs16Color := GetSystemColorBitDepth = 4;

  if not InhibitGradient then
  begin
    if FUsingDefaultGradientStopColor then
      FGradientStopColor := clActiveCaption;
    if FUsingDefaultGradientInactiveStopColor then
      FGradientInactiveStopColor := clInactiveCaption;
    CalculateColors;
    // This only goes to top-level windows so we have to feed it to MDI children
    if FormStyle = fsMDIForm then
    begin
      for x := 0 to MDIChildCount-1 do
        if MDIChildren[x] is TdfsGradientForm then
          TdfsGradientForm(MDIChildren[x]).WMSysColorChange(Msg);
    end;
  end;
  inherited;
end;

// The window has been resized.
procedure TdfsGradientForm.WMSize(var Msg: TWMSize);
begin
  inherited;
  if not InhibitGradient then
  begin
    // If the window was maximized or restored, we need to redraw so the right
    // caption button is painted.
    if (Msg.SizeType = SIZE_MAXIMIZED) or (Msg.SizeType = SIZE_RESTORED) then
      Draw(IsActiveWindow);
  end;
end;

// Windows would like to have a cursor displayed.  I know, you're wondering
// why the hell I care about this, aren't you?  Well, in the inherited handling
//  (default Windows processing) of this message, if the mouse is over a
// resizeable border section, Windows repaints the caption buttons.  Why?  I
// have absolutely no idea.  However, that's not the important part.  When it
// repaints those buttons, it also repaints the background around them in the
// last color it painted the caption in.  Now, usually this would just result
// in losing a few bands of the caption gradient, which 99.44% of all users
// would never notice.  However, because we don't always allow default
// processing of WM_NCACTIVATE, sometimes Windows doesn't have the right idea
// about which color is currently the background.  This cause the background to
// get painted in the wrong color sometimes, which 99.44% of all users *will*
// notice.  We fix it by setting the appropriate cursor and not allowing the
// default processing to occur.
procedure TdfsGradientForm.WMSetCursor(var Msg: TWMSetCursor);
begin
  if not InhibitGradient then
  begin
    // Tell Windows we handled the message
    Msg.Result := 1;
    // Load and display the correct cursor for the border area being hit
    case Msg.HitTest of
      HTTOP,
      HTBOTTOM:      SetCursor(LoadCursor(0, MakeIntResource(IDC_SIZENS)));
      HTLEFT,
      HTRIGHT:       SetCursor(LoadCursor(0, MakeIntResource(IDC_SIZEWE)));
      HTTOPRIGHT,
      HTBOTTOMLEFT:  SetCursor(LoadCursor(0, MakeIntResource(IDC_SIZENESW)));
      HTTOPLEFT,
      HTBOTTOMRIGHT: SetCursor(LoadCursor(0, MakeIntResource(IDC_SIZENWSE)));
    else
      // Wasn't anything we cared about, so tell Windows we didn't handle it.
      Msg.Result := 0;
      inherited;
    end;
  end else
    inherited;
end;


procedure TdfsGradientForm.WMSetText(var Msg: TWMSetText);
var
  FlagSet: boolean;
  Wnd: HWND;
begin
  if (not InhibitGradient) then
  begin
    Wnd := 0;
    if ((FormStyle = fsMDIChild) and (WindowState = wsMaximized)) then
    begin
      // Need to cause main form's caption to be redrawn, not the MDI child.
      if Application.MainForm.HandleAllocated then
        Wnd := Application.MainForm.Handle;
    end else begin
      if HandleAllocated then
        Wnd := Handle;
    end;

    if (Wnd <> 0) and IsWindowVisible(Wnd) then
    begin
      FlagSet := TRUE;
      // No update region for the window.  changes won't be painted.
      SetWindowRgn(Wnd, CreateRectRgn(0, 0, 0, 0), FALSE);
    end else
      FlagSet := FALSE;

    // Normally, processing WM_SETTEXT would cause all sorts of flicker as it
    // changed the caption text of the window.  But, we've told it that the
    // update region for the window (the portion it is allowed to paint in) is
    // a NULL region (a rectangle equal to 0, 0, 0, 0).  So, the changes don't
    // have anywhere to paint now, so it is safe to call inherited at this
    // point.  After that, we'll restore the window region so that painting
    // can happen again.
    inherited;

    if FlagSet then
      // Reset region to normal.
      SetWindowRgn(Wnd, 0, FALSE);

    // Don't do it if it was called from .SetCaption
    if not EntrancyFlag then
      Caption := Msg.Text;
  end else
    inherited;
end;

procedure TdfsGradientForm.WMGetText(var Msg: TWMGetText);
begin
  if not InhibitGradient then
  begin
    StrLCopy(Msg.Text, PChar(FCaptionText), Msg.TextMax-1);
    Msg.Result := StrLen(Msg.Text)+1;
  end else
    inherited;
end;

procedure TdfsGradientForm.WMGetTextLength(var Msg: TWMGetTextLength);
begin
  if not InhibitGradient then
  begin
    Msg.Result := Length(FCaptionText);
  end else
    inherited;
end;

procedure TdfsGradientForm.WMSettingChange(var Msg: TMessage);
begin
  if not InhibitGradient then
  begin
    // User might have changed NC font.
    if Msg.wParam = SPI_SETNONCLIENTMETRICS then
      UpdateCaptionFont;
//**      CreateCaptionFontHandle;
  end;
  inherited;
end;

{: This procedure is used to paint the caption gradient.  It is normally
   called internally, but it can be used any time a repaint of the caption
   is needed. The <B>Active</B> parameter is used to indicate whether the
   caption should be painted as the active window or an inactive window. }
procedure TdfsGradientForm.Draw(Active: boolean);
var
  DC: HDC;
begin
  if csDestroying in ComponentState then exit;
  
  // Get the DC we need to paint in.  GetDC would only get the DC for the
  // client area, we need it for non-client area, too, so we use GetWindowDC.
  DC := GetWindowDC(Handle);
  try
    DrawCaption(DFS_HDC(DC), Active);
  finally
    ReleaseDC(Handle, DC); // NEVER leave this hanging.
  end;
end;

procedure TdfsGradientForm.GradClientWndProc(var Message: TMessage);
begin
  with Message do begin
    Result := CallWindowProc(FGradDefClientProc, ClientHandle, Msg, wParam,
       lParam);
    // if you don't want your MDI child forms to be TdfsGradientForm descendants,
    // you will need to use uncomment the code in the following line.
    // It will work, but it causes an annoying flicker.
    // NOTE:  as of v1.55, this is no longer necessary.  Just leave it the way
    //        it is....I think.....

    // $003F is a "Magic Number".  I hate this, but it's the only way I could
    // get it to work.  :(
    if {(Msg = WM_MDIREFRESHMENU) or} (Msg = $003F) then
      Draw(IsActiveWindow);
  end;
end;

procedure TdfsGradientForm.WMNCLButtonDown(var Msg: TWMNCLButtonDown);
begin
  inherited;
  if not InhibitGradient then
    Draw(IsActiveWindow);
end;

procedure TdfsGradientForm.WMSysCommand (var Msg : TWMSysCommand);
begin
  if not InhibitGradient then
  begin
    if Msg.CmdType = SC_CONTEXTHELP then
      // Help button pressed, do't call Draw() because it will draw it in the up state.
      inherited
    else
    begin
      Draw(IsActiveWindow);
      inherited;
      Draw(IsActiveWindow);
    end;
  end else
    inherited;
end;

procedure TdfsGradientForm.WMEnterIdle(var Msg: TWMEnterIdle);
begin
  if not InhibitGradient then
    Draw(IsActiveWindow);
  inherited;
end;

procedure TdfsGradientForm.WMWindowPosChanging(var Msg: TWMWindowPosChanging);
begin
  with Msg.WindowPos^ do
    if FCreating and ((Flags and SWP_HIDEWINDOW) <> 0) then
      Flags := Flags or SWP_NOREDRAW;
  inherited;
end;

function TdfsGradientForm.StoreGradientStopColor: boolean;
begin
  Result := not FUsingDefaultGradientStopColor;
end;

function TdfsGradientForm.StoreGradientInactiveStopColor: boolean;
begin
  Result := not FUsingDefaultGradientInactiveStopColor;
end;

function TdfsGradientForm.Win98Check: boolean;
begin
  // Are we running under Win98, and should we let it do it for us?
  Result := FUseWin98Gradient and FRunningOnWin98;
end;

function TdfsGradientForm.GetVersion: string;
begin
  Result := DFS_COMPONENT_VERSION;
end;

procedure TdfsGradientForm.SetVersion(const Val: string);
begin
  { empty write method, just needed to get it to show up in Object Inspector }
end;

procedure TdfsGradientForm.Activate;
begin
  FChangingActivationState := TRUE;
  try
    inherited Activate;
  finally
    FChangingActivationState := FALSE;
  end;
end;

procedure TdfsGradientForm.Deactivate;
begin
  FChangingActivationState := TRUE;
  try
    inherited Deactivate;
  finally
    FChangingActivationState := FALSE;
  end;
end;

procedure TdfsGradientForm.DoShow;
begin
  FChangingActivationState := TRUE;
  try
    inherited DoShow;
  finally
    FChangingActivationState := FALSE;
  end;
end;


function TdfsGradientForm.GetSystemColorBitDepth: integer;
var
  DC: HDC;
begin
  DC := GetDC(0);
  try
    Result := (GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL));
  finally
    ReleaseDC(0, DC);
  end;
end;

function TdfsGradientForm.GetInhibitGradient: boolean;
begin
  Result := Win98Check or (SystemIs16Color and (not Paint16Color));
end;

procedure TdfsGradientForm.SetPaint16Color(const Value: boolean);
begin
  if FPaint16Color <> Value then
  begin
    FPaint16Color := Value;
    InvalidateCaption;
  end;
end;


procedure TdfsGradientForm.SetCaptionFont(const Value: TFont);
begin
  FCaptionFont.Assign(Value);
  UseSystemCaptionFont := FALSE;
  UpdateCaptionFont;
end;

function TdfsGradientForm.GetSysCaptionLogFont: TLogFont;
var
  NCM: TNonClientMetrics;
begin
  FillChar(Result, SizeOf(Result), #0);
  NCM.cbSize := SizeOf(NCM);
  if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NCM, 0) then
  begin
    if BorderStyle in [bsToolWindow, bsSizeToolWin] then
      Result := NCM.lfSmCaptionFont
    else
      Result := NCM.lfCaptionFont;
  end;
end;

procedure TdfsGradientForm.SetUseSystemCaptionFont(const Value: boolean);
begin
  if FUseSystemCaptionFont <> Value then
  begin
    FUseSystemCaptionFont := Value;
    UpdateCaptionFont;
  end;
end;


procedure TdfsGradientForm.UpdateCaptionFont;
var
  CF: TLogFont;
  NCM: TNonClientMetrics;
  FS: TFontStyles;
begin
  CF := GetSysCaptionLogFont;
  if FUseSystemCaptionFont then
  begin
    NCM.cbSize := SizeOf(NCM);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NCM, 0);
    {$IFDEF DFS_COMPILER_3_UP}
    FCaptionFont.Charset := TFontCharset(CF.lfCharSet);
    {$ENDIF}
    FCaptionFont.Name := CF.lfFaceName;
    FCaptionFont.Height := CF.lfHeight;
    case CF.lfPitchAndFamily and $F of
      VARIABLE_PITCH: FCaptionFont.Pitch := fpVariable;
      FIXED_PITCH: FCaptionFont.Pitch := fpFixed;
    else
      FCaptionFont.Pitch := fpDefault;
    end;
    FS := [];
    if CF.lfWeight >= FW_BOLD then
      Include(FS, fsBold);
    if CF.lfItalic = 1 then
      Include(FS, fsItalic);
    if CF.lfUnderline = 1 then
      Include(FS, fsUnderline);
    if CF.lfStrikeOut = 1 then
      Include(FS, fsStrikeOut);
    FCaptionFont.Style := FS;
  end else
    FCaptionFont.Height := CF.lfHeight;

  InvalidateCaption;
end;

procedure TdfsGradientForm.SetInactiveLogo(const Value: TBitmap);
begin
  FInactiveLogo.Assign(Value);
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetLogo(const Value: TBitmap);
begin
  FLogo.Assign(Value);
  InvalidateCaption;
end;

procedure TdfsGradientForm.SetLogoAlign(const Value: TGFLogoAlign);
begin
  if FLogoAlign <> Value then
  begin
    FLogoAlign := Value;
    InvalidateCaption;
  end;
end;

procedure TdfsGradientForm.SetLogoLayered(const Value: Boolean);
begin
  if FLogoLayered <> Value then
  begin
    FLogoLayered := Value;
    InvalidateCaption;
  end;
end;

procedure TdfsGradientForm.InvalidateCaption;
begin
  if HandleAllocated and not InhibitGradient then
  begin
    // Make the non client area repaint.
    SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_DRAWFRAME or SWP_NOACTIVATE or
      SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER);
   end;
end;

initialization
  EntrancyFlag := FALSE;
end.

