Skip to content

Commit 845f770

Browse files
authored
Merge 8962f15 into 16bc6e0
2 parents 16bc6e0 + 8962f15 commit 845f770

12 files changed

Lines changed: 189 additions & 1 deletion

CefSharp.Core.Runtime.RefAssembly/CefSharp.Core.Runtime.netcore.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//------------------------------------------------------------------------------
1+
//------------------------------------------------------------------------------
22
// <auto-generated>
33
// This code was generated by a tool.
44
// GenAPI Version: 5.0.2.37403
@@ -291,6 +291,7 @@ protected virtual void Dispose(bool A_0) { }
291291
public virtual System.Threading.Tasks.Task<CefSharp.ResolveCallbackResult> ResolveHostAsync(System.Uri origin) { throw null; }
292292
public virtual void SetContentSetting(string requestingUrl, string topLevelUrl, CefSharp.Enums.ContentSettingTypes contentType, CefSharp.Enums.ContentSettingValues value) { }
293293
public virtual bool SetPreference(string name, object value, out string error) { throw null; }
294+
public virtual CefSharp.IRegistration AddPreferenceObserver(string name, CefSharp.Callback.IPreferenceObserver observer) { throw null; }
294295
public virtual void SetWebsiteSetting(string requestingUrl, string topLevelUrl, CefSharp.Enums.ContentSettingTypes contentType, object value) { }
295296
public virtual CefSharp.IRequestContext UnWrap() { throw null; }
296297
}

CefSharp.Core.Runtime/CefSharp.Core.Runtime.netcore.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@
418418
<ClInclude Include="Internals\CefRequestContextHandlerAdapter.h" />
419419
<ClInclude Include="PostData.h" />
420420
<ClInclude Include="PostDataElement.h" />
421+
<ClInclude Include="Internals\PreferenceObserverAdapter.h" />
421422
<ClInclude Include="Request.h" />
422423
<ClInclude Include="resource.h" />
423424
<ClInclude Include="UrlRequest.h" />

CefSharp.Core.Runtime/CefSharp.Core.Runtime.netcore.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@
325325
<ClInclude Include="Internals\CefTaskDelegate.h">
326326
<Filter>Header Files</Filter>
327327
</ClInclude>
328+
<ClInclude Include="Internals\PreferenceObserverAdapter.h">
329+
<Filter>Header Files</Filter>
330+
</ClInclude>
328331
</ItemGroup>
329332
<ItemGroup>
330333
<ClInclude Include="Internals\CefFrameWrapper.h">

CefSharp.Core.Runtime/CefSharp.Core.Runtime.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@
317317
<ClInclude Include="Internals\CefRequestContextHandlerAdapter.h" />
318318
<ClInclude Include="PostData.h" />
319319
<ClInclude Include="PostDataElement.h" />
320+
<ClInclude Include="Internals\PreferenceObserverAdapter.h" />
320321
<ClInclude Include="Request.h" />
321322
<ClInclude Include="resource.h" />
322323
<ClInclude Include="UrlRequest.h" />

CefSharp.Core.Runtime/CefSharp.Core.Runtime.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@
319319
<ClInclude Include="Internals\CefTaskDelegate.h">
320320
<Filter>Header Files</Filter>
321321
</ClInclude>
322+
<ClInclude Include="Internals\PreferenceObserverAdapter.h">
323+
<Filter>Header Files</Filter>
324+
</ClInclude>
322325
<ClInclude Include="Internals\CefPermissionPromptCallbackWrapper.h">
323326
<Filter>Header Files</Filter>
324327
</ClInclude>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright © 2026 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
#include "include/cef_preference.h"
6+
#include <gcroot.h>
7+
8+
#include "StringUtils.h"
9+
10+
using namespace CefSharp::Callback;
11+
12+
namespace CefSharp
13+
{
14+
namespace Internals
15+
{
16+
private class PreferenceObserverAdapter : public CefPreferenceObserver
17+
{
18+
private:
19+
gcroot<IPreferenceObserver^> _handler;
20+
21+
public:
22+
PreferenceObserverAdapter(IPreferenceObserver^ handler)
23+
{
24+
_handler = handler;
25+
}
26+
27+
~PreferenceObserverAdapter()
28+
{
29+
delete _handler;
30+
_handler = nullptr;
31+
}
32+
33+
virtual void OnPreferenceChanged(const CefString& name) override
34+
{
35+
_handler->OnPreferenceChanged(StringUtils::ToClr(name));
36+
}
37+
38+
IMPLEMENT_REFCOUNTINGM(PreferenceObserverAdapter);
39+
};
40+
}
41+
}

CefSharp.Core.Runtime/RequestContext.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
#include "Internals\CefSchemeHandlerFactoryAdapter.h"
1212
#include "Internals\CefCompletionCallbackAdapter.h"
1313
#include "Internals\CefResolveCallbackAdapter.h"
14+
#include "Internals\PreferenceObserverAdapter.h"
1415
#include "Internals\TypeConversion.h"
16+
#include "Internals\CefRegistrationWrapper.h"
1517

1618
using namespace System::Runtime::InteropServices;
19+
using namespace CefSharp::Callback;
1720

1821
namespace CefSharp
1922
{
@@ -117,6 +120,17 @@ namespace CefSharp
117120
return success;
118121
}
119122

123+
IRegistration^ RequestContext::AddPreferenceObserver(String^ name, IPreferenceObserver^ observer)
124+
{
125+
ThrowIfDisposed();
126+
127+
ThrowIfExecutedOnNonCefUiThread();
128+
129+
auto registration = _requestContext->AddPreferenceObserver(StringUtils::ToNative(name), new PreferenceObserverAdapter(observer));
130+
131+
return gcnew CefRegistrationWrapper(registration);
132+
}
133+
120134
void RequestContext::ClearCertificateExceptions(ICompletionCallback^ callback)
121135
{
122136
ThrowIfDisposed();

CefSharp.Core.Runtime/RequestContext.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
using namespace System::Runtime::InteropServices;
1818
using namespace System::Threading::Tasks;
19+
using namespace CefSharp::Callback;
1920

2021
namespace CefSharp
2122
{
@@ -254,6 +255,23 @@ namespace CefSharp
254255
/// application thread will be the CEF UI thread.</remarks>
255256
virtual bool CanSetPreference(String^ name);
256257

258+
/// <summary>
259+
/// Add an observer for preference changes. <paramref name="name"/> is the name of the
260+
/// preference to observe. If <paramref name="name"/> is empty then all preferences will
261+
/// be observed. Observing all preferences has performance consequences and
262+
/// is not recommended outside of testing scenarios. The observer will remain
263+
/// registered until the returned Registration object is destroyed. This
264+
/// method must be called on the browser process UI thread.
265+
/// </summary>
266+
/// <param name="name">preference key</param>
267+
/// <param name="observer">preference observer</param>
268+
/// <remarks>Use Cef.UIThreadTaskFactory to execute this method if required,
269+
/// <see cref="IBrowserProcessHandler.OnContextInitialized"/> and ChromiumWebBrowser.IsBrowserInitializedChanged are both
270+
/// executed on the CEF UI thread, so can be called directly.
271+
/// When CefSettings.MultiThreadedMessageLoop == false (the default is true) then the main
272+
/// application thread will be the CEF UI thread.</remarks>
273+
virtual IRegistration^ AddPreferenceObserver(String^ name, IPreferenceObserver^ observer);
274+
257275
/// <summary>
258276
/// Set the value associated with preference name. If value is null the
259277
/// preference will be restored to its default value. If setting the preference

CefSharp.Core/RequestContext.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Threading.Tasks;
10+
using CefSharp.Callback;
1011
using CefSharp.Enums;
1112

1213
namespace CefSharp
@@ -174,6 +175,12 @@ public bool SetPreference(string name, object value, out string error)
174175
return requestContext.SetPreference(name, value, out error);
175176
}
176177

178+
/// <inheritdoc/>
179+
public IRegistration AddPreferenceObserver(string name, IPreferenceObserver observer)
180+
{
181+
return requestContext.AddPreferenceObserver(name, observer);
182+
}
183+
177184
/// <inheritdoc/>
178185
public void ClearCertificateExceptions(ICompletionCallback callback)
179186
{

CefSharp.Test/Framework/RequestContextTests.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.IO;
77
using System.Threading.Tasks;
8+
using CefSharp.Callback;
89
using CefSharp.Enums;
910
using CefSharp.Example;
1011
using CefSharp.Internals;
@@ -101,5 +102,62 @@ await CefThread.ExecuteOnUiThread(() =>
101102

102103
Assert.Equal(ContentSettingValues.Allow, (ContentSettingValues)actual);
103104
}
105+
106+
[Fact]
107+
public async Task CanObservePreferenceChange()
108+
{
109+
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
110+
111+
var ctx = RequestContext.Configure()
112+
.WithCachePath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Tests\\TempCache5"))
113+
.OnInitialize((ctx) =>
114+
{
115+
tcs.SetResult(true);
116+
})
117+
.Create();
118+
119+
await tcs.Task;
120+
121+
const string preferenceName = "autofill.enabled";
122+
object actual = null;
123+
var changeTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
124+
125+
await CefThread.ExecuteOnUiThread(() =>
126+
{
127+
ctx.SetPreference(preferenceName, true, out _);
128+
ctx.AddPreferenceObserver(preferenceName, new TestPreferenceObserver((name) =>
129+
{
130+
if (name == preferenceName)
131+
{
132+
actual = ctx.GetPreference(name);
133+
134+
changeTcs.TrySetResult(true);
135+
}
136+
}));
137+
138+
ctx.SetPreference(preferenceName, false, out _);
139+
});
140+
141+
await changeTcs.Task;
142+
143+
Assert.Equal(false, (bool)actual);
144+
}
145+
146+
private class TestPreferenceObserver : IPreferenceObserver
147+
{
148+
private readonly Action<string> onChanged;
149+
150+
public TestPreferenceObserver(Action<string> _onChanged)
151+
{
152+
onChanged = _onChanged;
153+
}
154+
155+
public void OnPreferenceChanged(string name)
156+
{
157+
onChanged?.Invoke(name);
158+
}
159+
160+
public void Dispose() { }
161+
}
104162
}
105163
}

0 commit comments

Comments
 (0)