Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sometimes fyne fails to setup dark mode #4758

Closed
2 tasks done
lostdusty opened this issue Mar 31, 2024 · 11 comments
Closed
2 tasks done

Sometimes fyne fails to setup dark mode #4758

lostdusty opened this issue Mar 31, 2024 · 11 comments
Labels
bug Something isn't working

Comments

@lostdusty
Copy link
Contributor

Checklist

  • I have searched the issue tracker for open issues that relate to the same problem, before opening a new one.
  • This issue only relates to a single bug. I will open new issues for any other problems.

Describe the bug

Happens randomly, with error code 0x800703e6.
image
Dark mode, however, is still set successfully.

How to reproduce

Use go run . until it appears. Depends on your luck I guess.

Screenshots

No response

Example code

func main() {
	a := app.New()
	w := a.NewWindow("Hello")

	hello := widget.NewLabel("Hello Fyne!")
	w.SetContent(container.NewVBox(
		hello,
		widget.NewButton("Hi!", func() {
			hello.SetText("Welcome :)")
		}),
	))

	w.ShowAndRun()
}

Fyne version

2.4.4

Go compiler version

1.22.0

Operating system and version

Windows 10

Additional Information

Modified internal/driver/glfw/window_windows.go to show the error code.

@lostdusty lostdusty added the unverified A bug that has been reported but not verified label Mar 31, 2024
@montovaneli
Copy link
Contributor

montovaneli commented Apr 3, 2024

Sometimes this also happens here. Even though the theme is correctly set in the 'fyne elements', the Windows' own window top bar remains in light theme, as in the print below (exactly when it occurred). It throws the same error 0x800703e6.

image

The right behavior for the window would be:

image

I read the error HRESULT =0x800703e6 represents - ERROR_NOACCESS. A description of the code reveals the message invalid access to memory location.

Perhaps a possibility is that the window fyne tries to set to dark mode isn't fully initialized yet?

I take this opportunity to ask you: Were you using the SystemTray or SystemTrayMenu API when this occurred?

@lostdusty
Copy link
Contributor Author

I were using none of them. At least on my machine the theme is still applied successfully, and I get the following error description: "The operation completed successfully."

@lostdusty
Copy link
Contributor Author

While developing, happened to me too:
image

@andydotxyz
Copy link
Member

Any error message logged?

@lostdusty
Copy link
Contributor Author

The operation completed successfully

@andydotxyz
Copy link
Member

OMG windows.

I wonder if there is something in the thread handling where we set that up... possibly we knocked it into a goroutine?

@andydotxyz
Copy link
Member

OMG windows.

I wonder if there is something in the thread handling where we set that up... possibly we knocked it into a goroutine?

Seems not:

	runOnMain(func() {
		w.setDarkMode()

Perhaps there is something in our windows call that is not correct for all systems or at all times?

		dwm := syscall.NewLazyDLL("dwmapi.dll")
		setAtt := dwm.NewProc("DwmSetWindowAttribute")
		ret, _, err := setAtt.Call(uintptr(unsafe.Pointer(hwnd)), // window handle
			20,                             // DWMWA_USE_IMMERSIVE_DARK_MODE
			uintptr(unsafe.Pointer(&dark)), // on or off
			8)                              // sizeof(darkMode)

@Jacalz
Copy link
Member

Jacalz commented Jun 8, 2024

I have a vague recollection of this being a thing on old versions of Windows 10 (or at least something similar). Is the system updated to the latest version?

@andydotxyz andydotxyz mentioned this issue Sep 3, 2024
2 tasks
@steampoweredtaco
Copy link
Contributor

In my case I get this error randomly as well but I am not even setting dark mode in the app anywhere.
image
To add some more info, I am using windows 10. My windows version is only a single patch out of date, but of course it is still Windows 10, not 11.

Edition	Windows 10 Pro
Version	22H2
Installed on	‎12/‎16/‎2022
OS build	19045.4894
Experience	Windows Feature Experience Pack 1000.19060.1000.0

image

@steampoweredtaco
Copy link
Contributor

steampoweredtaco commented Oct 5, 2024

I debugged the issue and found the return code was: 0x800703e6

More info, that error code is this:

Err_6.4.5.exe 0x800703e6
# No results found for hex 0x800703e6 / decimal -2147023898
# as an HRESULT: Severity: FAILURE (1), FACILITY_WIN32 (0x7), Code 0x3e6
# for hex 0x3e6 / decimal 998
  ERROR_NOACCESS                                                 winerror.h
# Invalid access to memory location.
# 1 matches found for "0x800703e6"

So, looking at the original code I noticed it is passing Bool unsafe with a size of 8. I think there are a few issues with this as I explain here in comments:

func (w *window) setDarkMode() {
	if runtime.GOOS == "windows" {
		hwnd := w.view().GetWin32Window()
		dark := isDark() // <-----returns go bool, one byte

		dwm := syscall.NewLazyDLL("dwmapi.dll")
		setAtt := dwm.NewProc("DwmSetWindowAttribute")
		ret, _, err := setAtt.Call(uintptr(unsafe.Pointer(hwnd)), // window handle
			20,                             // DWMWA_USE_IMMERSIVE_DARK_MODE
			uintptr(unsafe.Pointer(&dark)), // on or off
			8)                              // <---- 8 is too big, it will access invalid memory depending where isDark return is allocated.
			                                 //   explains the random nature. Also explains why other people sometimes see the title bar
                                                         //  the wrong color, it is because it is reading other data that make the bool true in windows
                                                         // api call because the byte that is actually used under the convers is 0 even if dark == true

		if ret != 0 && ret != 0x80070057 { // err is always non-nil, we check return value (except erroneous code)
			fyne.LogError(fmt.Sprintf("Failed to set dark mode, ret 0x%x", ret), err) <--- what I used to get the return code
		}
	}
}

So, based on my reasoning above this is the code I came up with.

func (w *window) setDarkMode() {
	if runtime.GOOS == "windows" {
		hwnd := w.view().GetWin32Window()
		dark := isDark()
                // cannot use a go bool.
		var winBool int32
		if dark {
			winBool = 1
		}
		dwm := syscall.NewLazyDLL("dwmapi.dll")
		setAtt := dwm.NewProc("DwmSetWindowAttribute")
		ret, _, err := setAtt.Call(uintptr(unsafe.Pointer(hwnd)), // window handle
			20,                             // DWMWA_USE_IMMERSIVE_DARK_MODE
			uintptr(unsafe.Pointer(&winBool)), // on or off
			4)                              // sizeof(bool for windows)

		if ret != 0 && ret != 0x80070057 { // err is always non-nil, we check return value (except erroneous code)
			fyne.LogError("Failed to set dark mode", err)
		}
	}
}

The above code works for my machine, windows 10. I think there is some out of date document implying DWMWA_USE_IMMERSIVE_DARK_MODE only works starting windows 11, but I think they added this in a newer windows 10 patch, I am just unsure when. However, the check for 0x80070057 catches the case for versions where windows 10 isn't supported.

Anyway, I think these are the correct changes that should work on windows 10 and window 11 and shouldn't randomly give these errors or make the title bar the wrong color (it could be white or black with the opposite theme with this bug).

steampoweredtaco pushed a commit to steampoweredtaco/fyne that referenced this issue Oct 5, 2024
…SetWindowAttribute and DWMWA_USE_IMMERSIVE_DARK_MODE on windows.
steampoweredtaco added a commit to steampoweredtaco/fyne that referenced this issue Oct 5, 2024
…SetWindowAttribute and DWMWA_USE_IMMERSIVE_DARK_MODE on windows.
steampoweredtaco added a commit to steampoweredtaco/fyne that referenced this issue Oct 5, 2024
…SetWindowAttribute and DWMWA_USE_IMMERSIVE_DARK_MODE on windows.
andydotxyz added a commit that referenced this issue Oct 5, 2024
…-4758

Fixes #4758, set the correct parameter memory and size for DwmSetWindowAttribute and DWMWA_USE_IMMERSIVE_DARK_MODE on windows.
@andydotxyz
Copy link
Member

Thanks to @steampoweredtaco this is fixed on develop, and I will pick it onto release branch

@andydotxyz andydotxyz added bug Something isn't working and removed unverified A bug that has been reported but not verified labels Oct 5, 2024
@andydotxyz andydotxyz added this to the E fixes (v2.5.x) milestone Oct 5, 2024
andydotxyz pushed a commit to andydotxyz/fyne that referenced this issue Oct 10, 2024
…SetWindowAttribute and DWMWA_USE_IMMERSIVE_DARK_MODE on windows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants
@andydotxyz @Jacalz @montovaneli @lostdusty @steampoweredtaco and others