NO

Author Topic: Enable Dark Mode for Title bar  (Read 15211 times)

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Enable Dark Mode for Title bar
« on: January 07, 2024, 08:43:42 AM »
This will turn on Dark Mode for the window title bar.

Code: [Select]
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")

#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif

static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg)
    {
        case WM_INITDIALOG:
        {
                // Enable dark mode title bar
                BOOL value = TRUE;
                DwmSetWindowAttribute(hwndDlg, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));

                ...

https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes#enable-a-dark-mode-title-bar-for-win32-applications

Toggle DarkMode/LightMode

Code: [Select]
BOOL isDarkModeEnabled = FALSE;

void ToggleDarkMode(HWND hWnd) {
    isDarkModeEnabled = !isDarkModeEnabled;

    // Enable or disable dark mode title bar
    BOOL value = isDarkModeEnabled;
    DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));

    RECT rc;
    GetWindowRect(hWnd, &rc);

    if (isDarkModeEnabled) {
        // Increase window size by 1 pixel
        MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left + 1, rc.bottom - rc.top + 1, TRUE);
    } else {
        // Decrease window size by 1 pixel
        MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left - 1, rc.bottom - rc.top - 1, TRUE);
    }
}

Turning Some Elements Dark
Undocumented - https://stackoverflow.com/a/53545935/2694720

Code: [Select]
#include <uxtheme.h>
#pragma comment(lib, "uxtheme.lib")

void ApplyDarkModeToControls(HWND hwnd, BOOL darkMode)
{
    HWND hChild = GetWindow(hwnd, GW_CHILD);

    while (hChild)
    {
        if (darkMode)
        {
            SetWindowTheme(hChild, L"DarkMode_Explorer", NULL);
        }
        else
        {
            SetWindowTheme(hChild, NULL, NULL);
        }

        ApplyDarkModeToControls(hChild, darkMode);
        hChild = GetWindow(hChild, GW_HWNDNEXT);
    }
}

void ToggleDarkMode(HWND hWnd)
{
    isDarkModeEnabled = !isDarkModeEnabled;

    // Enable or disable dark mode title bar
    BOOL value = isDarkModeEnabled;
    DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));

    // Apply the theme to all child controls recursively
    ApplyDarkModeToControls(hWnd, isDarkModeEnabled);

    RECT rc;
    GetWindowRect(hWnd, &rc);

    if (isDarkModeEnabled)
    {
        MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left + 1, rc.bottom - rc.top + 1, TRUE);
    }
    else
    {
        MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left - 1, rc.bottom - rc.top - 1, TRUE);
    }
}

I hope to actually implement a full window + full control solution

https://gist.github.com/rounk-ctrl/b04e5622e30e0d62956870d5c22b7017

Enjoy!
« Last Edit: January 07, 2024, 10:20:06 AM by WiiLF23 »

Offline John Z

  • Member
  • *
  • Posts: 865
Re: Enable Dark Mode for Title bar
« Reply #1 on: January 07, 2024, 09:22:39 PM »
Hi WiiLF23,

Thanks for the example and links.  I've not used uxtheme.lib so nice to see an example. 

In a program I gave the user the ability to create and save 5 themes themselves not dependent on the system theme but with some limitations. like the toolbar and menu.  Maybe I'll try uxtheme for them.

John Z

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Re: Enable Dark Mode for Title bar
« Reply #2 on: January 08, 2024, 02:17:28 AM »
Hi WiiLF23,

Thanks for the example and links.  I've not used uxtheme.lib so nice to see an example. 

In a program I gave the user the ability to create and save 5 themes themselves not dependent on the system theme but with some limitations. like the toolbar and menu.  Maybe I'll try uxtheme for them.

John Z

Most welcome! I am currently implementing the full experience and I have dark mode for Menu now. The only issue im having, is applying the menu theme by calling when desired. Menu only darkens when I call in WM_INITDIALOG message.

Current progress, working successfully for full menu dark mode:

Code: [Select]
typedef BOOL(WINAPI* fnShouldAppsUseDarkMode)();
typedef BOOL(WINAPI* fnAllowDarkModeForWindow)(HWND hWnd, BOOL allow);
typedef DWORD(WINAPI* fnSetPreferredAppMode)(DWORD appMode);

enum PreferredAppMode
{
    Default,
    AllowDark,
    ForceDark,
    ForceLight,
    Max
};

HMODULE hUxtheme;

fnShouldAppsUseDarkMode ShouldAppsUseDarkMode;
fnAllowDarkModeForWindow AllowDarkModeForWindow;
fnSetPreferredAppMode SetPreferredAppMode;

void InitDarkMode()
{
    hUxtheme = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
    if (hUxtheme)
    {
        ShouldAppsUseDarkMode = (fnShouldAppsUseDarkMode)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132));
        AllowDarkModeForWindow = (fnAllowDarkModeForWindow)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133));
        SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));
    }
}

WM_INITDIALOG:
Code: [Select]
InitDarkMode();
SetPreferredAppMode(ForceDark); // options in enum

WM_DESTROY:
Code: [Select]
FreeLibrary(hUxtheme);





« Last Edit: January 08, 2024, 02:42:44 AM by WiiLF23 »

Offline John Z

  • Member
  • *
  • Posts: 865
Re: Enable Dark Mode for Title bar
« Reply #3 on: January 08, 2024, 05:03:57 AM »
Hi WiiLF23,

The only issue im having, is applying the menu theme by calling when desired. Menu only darkens when I call in WM_INITDIALOG message.

Most Menu changes need to be followed up by  DrawMenuBar(gHWND);  might be worth a try.

John Z

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Re: Enable Dark Mode for Title bar
« Reply #4 on: January 08, 2024, 05:49:01 AM »
Redraw, Invalidate, DrawMenu all fail on the parent window. Its a strange issue. I read that Microsoft decided not to expose a lot of the API for dark mode for winapi so a lot of people have discussed it over time, not very happy with their findings etc but its intended for UWP apps, so its short of a miracle to get it this far at the moment.


At this point, I will keep the current dark controls possible, and paint the window and the rest of the controls accordingly. Starting to learn about this as we speak, I think this is the best option.

Code: [Select]
case WM_PAINT: {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwndDlg, &ps);

    // Set the background color to dark (black)
    SetBkColor(hdc, RGB(0, 0, 0));
    ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &ps.rcPaint, NULL, 0, NULL);

    EndPaint(hwndDlg, &ps);
    return 0;
}
« Last Edit: January 08, 2024, 05:54:05 AM by WiiLF23 »

Offline John Z

  • Member
  • *
  • Posts: 865
Re: Enable Dark Mode for Title bar
« Reply #5 on: January 08, 2024, 07:01:58 AM »
Hi WiiLF23,

I don't use WM_PAINT for colors.  Capturing and processing WM_CTLxxxx messages allows coloring everything except the toolbar background, the menu, and the outer dialog frame. 

Attached amateur spaghetti code excerpts are how I give users their own theme choices.
There is a minor complication in it in that the program also uses Blue as a notification so a user choosing the same blue has to be checked.  Otherwise straight forward capture and control.  There is also a separate procedure for child windows of the main form.
 
Probably does not add to your knowledge and capability but worth a shot.  :)

John Z

btw any color change is instantly reflected in the window . . . .
« Last Edit: January 08, 2024, 07:16:47 AM by John Z »

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Re: Enable Dark Mode for Title bar
« Reply #6 on: January 08, 2024, 07:38:06 AM »
Wow nice, I can certainly work with that , in fact that just about finalized the dark approach. Very interesting, thank you

Offline John Z

  • Member
  • *
  • Posts: 865
Re: Enable Dark Mode for Title bar
« Reply #7 on: January 08, 2024, 08:36:06 AM »
Hi WiiLF23,

Hope it helps.
In mine the user can set the colors at will so here is how the brushes are created once they select the color and it implements immediate .  The cases are from the menu dropdown shown.  Again excerpted from main message loop.  You will probably do a bit different if limited 'theme' choices.

John Z

Offline MrBcx

  • Global Moderator
  • Member
  • *****
  • Posts: 195
    • Bcx Basic to C/C++ Translator
Re: Enable Dark Mode for Title bar
« Reply #8 on: January 08, 2024, 03:48:28 PM »
The attached screenshot shows the progress that Armando Rivera and I made putting together some plug and play Dark Mode routines about a year ago.  The app in the screenshot was written by me over 20 years ago but converted to Dark Mode last year, as a proof of concept

The translated BCX code compiles and displays as shown using Pelles C v12. 
It also compiles and runs correctly using VS2022 with the Clang compiler.

Discussion thread: https://bcxbasiccoders.com/smf/index.php?topic=826.0

Bcx Basic to C/C++ Translator
https://www.BcxBasicCoders.com

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Re: Enable Dark Mode for Title bar
« Reply #9 on: January 08, 2024, 09:45:38 PM »
Thank you MrBcx, I have migrated the responsible code to a new dialog-based project, reducing a lot (cross-compiler declarations and other bits). Its also fully converted to handle Unicode.

Here is the project file for a basic GUI window.

I would like to clean it up, I realize a lot of what is left over is conversion support.

« Last Edit: January 08, 2024, 09:47:22 PM by WiiLF23 »

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Re: Enable Dark Mode for Title bar
« Reply #10 on: January 08, 2024, 10:12:41 PM »
Update:

Much cleaner, and right down to dark mode rendering I am after! This is perfect.

- Updated to be DPI aware (font smoothing). Fixes pixilated font edges.
- Removed redundant code  from source provided by MrBCX.

Enjoy!

Offline John Z

  • Member
  • *
  • Posts: 865
Re: Enable Dark Mode for Title bar
« Reply #11 on: January 08, 2024, 11:03:16 PM »
The attached screenshot shows the progress that Armando Rivera and I made putting together some plug and play Dark Mode routines about a year ago.  The app in the screenshot was written by me over 20 years ago but converted to Dark Mode last year, as a proof of concept

The translated BCX code compiles and displays as shown using Pelles C v12. 
It also compiles and runs correctly using VS2022 with the Clang compiler.

Discussion thread: https://bcxbasiccoders.com/smf/index.php?topic=826.0

Thanks MrBCX and Mr. Rivera!  Allowing use with attribution?

I tried just the Menu change procedure (which I could never get working before) in my program. Added MIM_APPLYTOSUBMENUS and seems to work but I've a little more to do in my case.  Also my font color does not carry over.

As always MrBCX provides education!

Thanks WiiLF23 - I got your functional extraction version too. Fairly sure I'm going to stick with my user defined system independent themes method but maybe I'll be able to set menu font color and toolbar colors now.

John Z

Offline MrBcx

  • Global Moderator
  • Member
  • *****
  • Posts: 195
    • Bcx Basic to C/C++ Translator
Re: Enable Dark Mode for Title bar
« Reply #12 on: January 08, 2024, 11:27:40 PM »

Allowing use with attribution?


Consider it Public Domain.  Attribution is always appreciated too.
Bcx Basic to C/C++ Translator
https://www.BcxBasicCoders.com

Offline WiiLF23

  • Member
  • *
  • Posts: 89
Re: Enable Dark Mode for Title bar
« Reply #13 on: January 08, 2024, 11:42:33 PM »
Many thanks, sorry I tend to piece together fast - I also dont leave many code comments at all as you notice, will be improving on this as I go.

Currently adding a Light/Dark toggle. 50% done but a few caveats

Offline MrBcx

  • Global Moderator
  • Member
  • *****
  • Posts: 195
    • Bcx Basic to C/C++ Translator
Re: Enable Dark Mode for Title bar
« Reply #14 on: January 08, 2024, 11:47:38 PM »
Many thanks, sorry I tend to piece together fast - I also dont leave many code comments at all as you notice, will be improving on this as I go.

Currently adding a Light/Dark toggle. 50% done but a few caveats

No worries! 

Knowledge, similar to light, works best when it is diffused.
Bcx Basic to C/C++ Translator
https://www.BcxBasicCoders.com