DwmExtendFrameIntoClientArea without Aero Glass

前端 未结 3 1273
遥遥无期
遥遥无期 2021-02-05 22:20

Using the DwmExtendFrameIntoClientArea API call with Aero Glass enabled works just fine. However, I want it to work when Aero Glass is disabled as well, like how it

相关标签:
3条回答
  • 2021-02-05 22:40

    Nir's answer is correct; when composition is disabled you have to draw that area yourself.

    i can show you the code i have in the paint handler of the panel at the top of my form - the panel normally responsible for drawing the 0x00000000 transparent black to make the glass appear:

    Psuedo-code:

    procedure DrawGlassHeaderArea(g: Graphics; r: Rectangle; IsFormFocused: Boolean);
    const
       clFakeGlassColor = $00EAD1B9;  //(185, 209, 234) This is the fake foreground glass color (for use when composition is disabled)
       clFakeGlassColorUnfocused = $00F2E4D7; //(215, 228, 242) This is the fake background glass color (for use when composition is disabled)
    begin
       if Dwm.IsCompositionEnabled then
       begin
          g.FillRectangle(r, 0x00000000); //fill rectangle with transparent black
       end
       else
          //Composition disabled; fake it like Microsoft does
    
          //The color to use depends if the form has focused or not
          Color glassColor;
          if (IsFormFocused) then
             c = clFakeGlassColor 
          else
             c = clFakeGlassColorUnfocused;
    
          g.FillRectangle(r, glassColor); //fill rectangle with fake color
    
    
          //Now we have to draw the two accent lines along the bottom
          Color edgeHighlight = ColorBlend(Colors.White, glassColor, 0.33); //mix 33% of glass color to white
          Color edgeShadow = ColorBlend(Colors.Black, glassColor, 0.33); //mix 33% of glass color to black
    
          //Draw highlight as 2nd-last row:
          g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-2), Point(r.Right, r.Bottom-2);
    
          //Draw shadow on the very last row:
          g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-1), Point(r.Right, r.Bottom-1);
       end;
    end;
    

    Sample usage

    procedure MyForm.PaintBox1Paint(PaintEventArgs e)
    begin
       DrawGlassHeaderArea(e.Graphics, PaintBox1.ClientRectangle, this.HasFocus); 
    end;
    

    Bonus Screenshot

    enter image description here

    Update 7/9/2014

    @JakePetroules was right, and i was wrong. The "blue" used for fake glass is not hard-coded into Windows. And it is accessible using GetThemeColor.

    I coded up all the available colors (TMT_COLOR) available for a Window class:

    enter image description here

    Note: For more information about Classes, Parts, and States, see Aero Style Classes, Parts, and States

    When using:

    • Class: Window
    • Part: WP_CAPTION
    • State: n/a (StateID is not used for the Caption part, nor the entire Window class)

    and fetch the color code propertyID:

    • TMT_FILLCOLORHINT: for when the window has focus
    • TMT_BORDERCOLORHINT: for when the window does not have focus

    you get the two important colors:

    enter image description here

    The pseudo-code i now use to get the fake glass color:

    public Color GetFakeClassColor(Boolean isWindowFocused=true)
    {
       static Color fakeGlass= 0x00B8D0E9; //the correct answer anyway
    
       if ((GetThemeAppProperties() && STAP_ALLOW_CONTROLS) == 0)
          return fakeGlass;
    
       hTheme = OpenThemeData(GetDesktopWindow(), "Window");
       if (hTheme = 0)
          return fakeGlass;
    
       Int32 propID;
       if (isWindowFocused)
           propID= TMT_FILLCOLORHINT; //The color used as a fill color hint for custom controls.
       else
           propID= TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.
    
       DWORD rgb;
       if (Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, ref rgb))
          return fakeGlass;
    
       Result = new Color(rgb);
    }
    

    In reality, since i use Delphi, my actual code is:

    function GetFakeGlassColor(IsWindowFocused: Boolean=True): TColor;
    var
        ted: TThemedElement;
        hTheme: THandle;
        propID: Integer;
        rgb: DWORD;
    begin
        Result := $00B8D0E9; //the correct answer anyway
    
        //We can't use the ThemeServcies.ThemesEnabled, as that mistakenly checks for version 6 of the common controls library
        //Themes can be enabled without using ComCtl V6, or common controls at all
        if not ThemeServices.ThemesAvailable then
            Exit;
        if (GetThemeAppProperties and STAP_ALLOW_CONTROLS) = 0 then
            Exit;
    
        htheme := ThemeServices.Theme[teWindow];
        if hTheme = 0 then
            Exit;
    
        if IsWindowFocused then
            propID := TMT_FILLCOLORHINT //The color used as a fill color hint for custom controls.
        else
            propID := TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.
    
        if Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, {var}rgb)) then
            Exit;
    
        Result := rgb;
    end;
    
    0 讨论(0)
  • 2021-02-05 22:47

    You need to paint the window background yourself. You should not actually hard-code the colors as previous posts have suggested, but use the theme functions to retrieve them, like so (semi-pseudocode):

    DWORD rgb;
    HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
    GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
        <is active window> ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);
    
    // Can use these functions to retrieve the individual RGB values
    BYTE r = GetRValue(rgb);
    BYTE g = GetGValue(rgb);
    BYTE b = GetBValue(rgb);
    

    These colors will remain correct even if the user changes title bar colors in the control panel (unlike using COLOR_ACTIVECAPTION / COLOR_GRADIENTACTIVECAPTION). You should also check that themes are active using IsThemeActive() before attempting to get theme colors.

    The values of the constants for quick reference:

    • WP_CAPTION: 1
    • CS_ACTIVE: 1
    • TMT_FILLCOLORHINT: 3821
    • TMT_BORDERCOLORHINT: 3822
    0 讨论(0)
  • 2021-02-05 23:04

    You have to paint it to be frame-like yourself.

    You have to use DwmIsCompositionEnabled to check if the DWM is enabled and handle WM_DWMCOMPOSITIONCHANGED to detect DWM state changed.

    Then you have to have to separate way of drawing the window, if DWM is enabled you use DwmExtendFrameIntoClientArea, if it's disabled you draw the "frame" yourself.

    I have no idea how to duplicate the Aero frame in WPF (in my app I have my own color scheme and I'm not using the Auro frame).

    This is annoying but when the DWM is disabled the system falls back to XP-style drawing and none of the DWM's services work - even those that aren't related to the glass effect.

    0 讨论(0)
提交回复
热议问题