rocksdanister / lively

Free and open-source software that allows users to set animated desktop wallpapers and screensavers powered by WinUI 3.
https://rocksdanister.com/lively
GNU General Public License v3.0
14.61k stars 1.04k forks source link

Display static wallpaper when cef is paused. #20

Closed rocksdanister closed 2 years ago

rocksdanister commented 4 years ago

Currently I'm minimizing the browser to let cef know to stop rendering, the side effect is the wallpaper region becomes black; there does not seem to be a function to stop rendering in non-headless cef as far as I can see.

Need to find a better solution, off the top of my head I can think of some ideas:

rocksdanister commented 4 years ago

Looks like its possible to get rendered bitmap: http://cefsharp.github.io/api/71.0.0/html/M_CefSharp_Wpf_ChromiumWebBrowser_OnPaint.htm

http://cefsharp.github.io/api/57.0.0/html/P_CefSharp_OffScreen_ChromiumWebBrowser_Bitmap.htm

amaitland commented 4 years ago

Looks like its possible to get rendered bitmap: http://cefsharp.github.io/api/71.0.0/html/M_CefSharp_Wpf_ChromiumWebBrowser_OnPaint.htm

http://cefsharp.github.io/api/57.0.0/html/P_CefSharp_OffScreen_ChromiumWebBrowser_Bitmap.htm

@rocksdanister Are you using the WinForms or WPF version of CefSharp?

rocksdanister commented 4 years ago

Winforms

amaitland commented 4 years ago

Looks like its possible to get rendered bitmap: http://cefsharp.github.io/api/71.0.0/html/M_CefSharp_Wpf_ChromiumWebBrowser_OnPaint.htm

http://cefsharp.github.io/api/57.0.0/html/P_CefSharp_OffScreen_ChromiumWebBrowser_Bitmap.htm

This is only possible in the WPF/OffScreen versions as each frame is rendered to a bitmap.

For the WinForms version it is possible to take a screenshot though this is often tricky.

Display static wallpaper when cef is paused.

Can you clarify what you mean by CEF paused?

rocksdanister commented 4 years ago

When fullscreen apps/games are run Lively will pause the wallpaper playback to reduce cpu/gpu usage.

LivelyCefsharp is a separate program (winform) from lively(wpf). I pass the window handle to lively using: GetBrowser().GetHost().GetWindowHandle() then set it as child window of the new WorkerW window between the WorkerW instance that holds the Desktop Icons (SysListView32) and the Desktop Manager.

In order to let cef know to stop rendering the page lively will do this: ShowWindow(cefhandle, SW_MINIMIZE); Problem is this leaves a blank black area on screen which is not pleasant as wallpaper especially with additional options in lively settings such as pause wallpaper playback when apps are open, when on battery power etc.

I was wondering if something like WasHidden possible in window rendering, but display the last rendered frame as a static wallpaper.. like a play/pause button for cefsharp.

I understand this is a niche case; most of the wallpapers are gpu accelerated, so wpf version of cefsharp was not feasible.

amaitland commented 4 years ago

Sorry for the late reply, WasHidden is only for WPF and OffScreen versions. Initially I didn't find anything particular helpful for the WinForms version. It's actually difficult to take a screenshot in WinForms, the only totally reliable option was to enable remote debugging and use DevTools protocol.

CEF recently added support for direct DevTools access, no need to enable remote debugging. So it's relatively trivial to take a screenshot starting from version 83.

I have been digging through the DevTools protocol documentation recently as there are lots of interesting new possibilities open to us.

https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-setWebLifecycleState looks interesting, potentially you can put the browser into a frozen state. I have yet to try this so it's purely speculative at this point.

See https://github.com/cefsharp/CefSharp/issues/3158#issuecomment-651004911 for link to example of taking screenshot. This might be the best option.

rocksdanister commented 4 years ago

I had a quick try with Page.setWebLifecylceState, this works:

id = await chromeBrowser.ExecuteDevToolsMethodAsync(0, "Page.setWebLifecycleState", new Dictionary<string, object> {{ "state", "frozen" }});

The usage drops and the view becomes background color (default: white.)

But when I try to unpause the paused page:

id = await chromeBrowser.ExecuteDevToolsMethodAsync(0, "Page.setWebLifecycleState", new Dictionary<string, object> {{ "state", "active" }});

it does not work, the id returned is non-zero.

This looks promising, adding the screenshot function ontop of this one should achieve what I'm looking for.

amaitland commented 4 years ago

You could potentially just take a screenshot and load that into the browser, then navigate back when you wish to resume.

rocksdanister commented 4 years ago

That would be unpleasant though, I tried about:blank in the past. Problem is process monitoring loop is checking every 500ms to see if any application is fullscreen so pause/unpause happen frequently, there will be loading delay(?) for the page and some users also use online webpages instead of offline version.

My other idea is to have two windows, one for the static picture and other for browser and when the browser window is minimized(paused) the static window is used to show the last captured screenshot... I was hoping to avoid this complication if Page.setWebLifecylceState worked.

amaitland commented 4 years ago

That would be unpleasant though, I tried about:blank in the past.

No idea how about:blank is related in this context? If you load the screenshot as a Data Uri then it should be pretty quick as no network call needs to be made.

I was hoping to avoid this complication if Page.setWebLifecylceState worked.

You'd need to try it in an equivalent version of Chrome to see what the expected behaviour is. Perhaps CEF requires additional handling to support this.

Via DevTools you can also pause/resume javascript execution. You can pause videos via javascript.

Just throwing some suggestions out there as I'm not familiar enough with your app to be specific.

rocksdanister commented 4 years ago

No idea how about:blank is related in this context? If you load the screenshot as a Data Uri then it should be pretty quick as no network call needs to be made.

What I tried in the past is load about:blank to pause execution and then navigate back to original page to unpause, problem was the loading back to original page took some time(especially if its online page) and this is very noticeable say when suddenly opening and closing windows explorer fullscreen and also this leads to webpage loses its saved state.

You'd need to try it in an equivalent version of Chrome to see what the expected behaviour is. Perhaps CEF requires additional handling to support this.

I tried with Chrome/85.0.4182.0 and the behavior looks the same, page is not unfreezing.

Via DevTools you can also pause/resume javascript execution. You can pause videos via javascript.

Not sure I understand, ~Debugger.pause? I tried and it worked but Debugger.resume does not work for some reason.~

Just throwing some suggestions out there as I'm not familiar enough with your app to be specific.

Help is appreciated.

rocksdanister commented 3 years ago

WebView2 (Chromium) implementation of this is ready and in production.

rocksdanister commented 2 years ago

@amaitland Calling DebugActiveProcess on "Intermediate D3D Window" CefSubProcess seems to do the trick.. working fine on my limited testing.

rocksdanister commented 2 years ago

Beta build is ready for testing: https://github.com/rocksdanister/lively-beta

ezgif com-gif-maker (2)

ezgif com-gif-maker

CEbbinghaus commented 2 years ago

Thank you so much. Looks really good 👍🏻