v0.33.1 9577fee

settings.go RawHistoryFolder

1package webkit
2
3import (
4	"context"
5	"sync"
6
7	"github.com/bnema/dumber/internal/domain/entity"
8	"github.com/bnema/dumber/internal/logging"
9	"github.com/bnema/puregotk/v4/webkit"
10	"github.com/rs/zerolog"
11)
12
13const hardwareRequiredContentTypes = "video/av01;video/mp4;video/webm;video/x-h264;video/x-h265"
14
15type mediaSettings interface {
16	SetEnableWebaudio(bool)
17	SetEnableWebgl(bool)
18	SetEnableMedia(bool)
19	SetEnableMediasource(bool)
20	SetEnableMediaCapabilities(bool)
21	SetEnableEncryptedMedia(bool)
22	SetMediaPlaybackRequiresUserGesture(bool)
23	SetMediaPlaybackAllowsInline(bool)
24	SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicy)
25	SetMediaContentTypesRequiringHardwareSupport(*string)
26}
27
28// SettingsManager creates and manages WebKit Settings instances from payloads.
29type SettingsManager struct {
30	settings entity.EngineSettingsPayload
31	mu       sync.RWMutex
32}
33
34// NewSettingsManager creates a new SettingsManager with the given payload.
35func NewSettingsManager(ctx context.Context, settings entity.EngineSettingsPayload) *SettingsManager {
36	log := logging.FromContext(ctx)
37	log.Debug().Msg("creating settings manager")
38	return &SettingsManager{settings: settings}
39}
40
41func (sm *SettingsManager) current() entity.EngineSettingsPayload {
42	sm.mu.RLock()
43	defer sm.mu.RUnlock()
44	return sm.settings
45}
46
47// CreateSettings creates a new webkit.Settings instance configured from the current payload.
48func (sm *SettingsManager) CreateSettings(ctx context.Context) *webkit.Settings {
49	log := logging.FromContext(ctx)
50	payload := sm.current()
51
52	settings := webkit.NewSettings()
53	if settings == nil {
54		log.Error().Msg("failed to create webkit settings")
55		return nil
56	}
57
58	sm.applySettings(ctx, settings, payload)
59	return settings
60}
61
62// applySettings applies settings payload to a webkit.Settings instance.
63func (sm *SettingsManager) applySettings(ctx context.Context, settings *webkit.Settings, payload entity.EngineSettingsPayload) {
64	if sm == nil {
65		return
66	}
67	log := logging.FromContext(ctx)
68	applyJavaScriptSettings(settings)
69	applyFontSettings(settings, payload.WebContent)
70	applyDebugSettings(settings, payload.WebContent)
71	applyBrowsingSettings(settings)
72	applyMediaSettings(settings, payload.WebContent.HardwareDecoding, log)
73	applyStorageSettings(settings)
74	applyUISettings(settings)
75	applyCanvasSettings(settings)
76	applyWebRTCSettings(settings)
77
78	webrtcEnabled := settings.GetPropertyEnableWebrtc()
79	mediaStreamEnabled := settings.GetPropertyEnableMediaStream()
80
81	log.Debug().
82		Str("sans_font", payload.WebContent.SansFont).
83		Bool("developer_extras", payload.WebContent.EnableDevTools).
84		Bool("webrtc_enabled", webrtcEnabled).
85		Bool("media_stream_enabled", mediaStreamEnabled).
86		Msg("settings applied")
87}
88
89func applyJavaScriptSettings(settings *webkit.Settings) {
90	settings.SetEnableJavascript(true)
91	settings.SetEnableJavascriptMarkup(true)
92}
93
94func applyFontSettings(settings *webkit.Settings, payload entity.EngineWebContentSettingsPayload) {
95	if payload.SansFont != "" {
96		settings.SetDefaultFontFamily(payload.SansFont)
97		settings.SetSansSerifFontFamily(payload.SansFont)
98	}
99	if payload.SerifFont != "" {
100		settings.SetSerifFontFamily(payload.SerifFont)
101	}
102	if payload.MonospaceFont != "" {
103		settings.SetMonospaceFontFamily(payload.MonospaceFont)
104	}
105	if payload.DefaultFontSize > 0 {
106		settings.SetDefaultFontSize(uint32(payload.DefaultFontSize))
107	}
108}
109
110func applyDebugSettings(settings *webkit.Settings, payload entity.EngineWebContentSettingsPayload) {
111	settings.SetEnableDeveloperExtras(payload.EnableDevTools)
112	settings.SetEnableWriteConsoleMessagesToStdout(payload.CaptureConsole)
113	settings.SetDrawCompositingIndicators(payload.DrawCompositingIndicators)
114}
115
116func applyBrowsingSettings(settings *webkit.Settings) {
117	settings.SetEnableSmoothScrolling(true)
118	settings.SetEnablePageCache(true)
119	settings.SetEnableSiteSpecificQuirks(true)
120}
121
122func applyMediaSettings(settings mediaSettings, mode entity.EngineHardwareDecodingMode, log *zerolog.Logger) {
123	settings.SetEnableWebaudio(true)
124	settings.SetEnableWebgl(true)
125	settings.SetEnableMedia(true)
126	settings.SetEnableMediasource(true)
127	settings.SetEnableMediaCapabilities(true)
128	settings.SetEnableEncryptedMedia(true)
129	settings.SetMediaPlaybackRequiresUserGesture(true)
130	settings.SetMediaPlaybackAllowsInline(true)
131
132	switch mode {
133	case entity.EngineHardwareDecodingForce:
134		hwTypes := hardwareRequiredContentTypes
135		settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyAlwaysValue)
136		settings.SetMediaContentTypesRequiringHardwareSupport(&hwTypes)
137		log.Debug().Msg("hardware decoding: forced (may fail without hw support)")
138	case entity.EngineHardwareDecodingDisable:
139		emptyTypes := ""
140		settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyNeverValue)
141		settings.SetMediaContentTypesRequiringHardwareSupport(&emptyTypes)
142		log.Debug().Msg("hardware decoding: disabled (software only)")
143	default:
144		emptyTypes := ""
145		settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyAlwaysValue)
146		settings.SetMediaContentTypesRequiringHardwareSupport(&emptyTypes)
147		log.Debug().Msg("hardware decoding: auto (hw preferred, software fallback)")
148	}
149}
150
151func applyStorageSettings(settings *webkit.Settings) {
152	settings.SetEnableHtml5LocalStorage(true)
153	settings.SetEnableHtml5Database(true)
154}
155
156func applyUISettings(settings *webkit.Settings) {
157	settings.SetEnableBackForwardNavigationGestures(true)
158	settings.SetEnableFullscreen(true)
159}
160
161func applyCanvasSettings(settings *webkit.Settings) {
162	settings.SetEnable2dCanvasAcceleration(true)
163}
164
165func applyWebRTCSettings(settings *webkit.Settings) {
166	// Set both direct API and gobject properties for robustness with generated bindings.
167	settings.SetPropertyEnableMediaStream(true)
168	settings.SetPropertyEnableWebrtc(true)
169
170	settings.SetEnableMediaStream(true)
171	settings.SetEnableWebrtc(true)
172}
173
174// UpdateFromPayload updates the manager with a new payload (for hot-reload).
175// Note: This doesn't update already-created Settings instances.
176// New WebViews will use the updated payload.
177func (sm *SettingsManager) UpdateFromPayload(ctx context.Context, settings entity.EngineSettingsPayload) {
178	log := logging.FromContext(ctx)
179	sm.mu.Lock()
180	defer sm.mu.Unlock()
181	sm.settings = settings
182	log.Debug().Msg("settings payload updated")
183}
184
185// ApplyToWebView applies current settings to an existing WebView.
186// This can be used to update a WebView's settings after config hot-reload.
187func (sm *SettingsManager) ApplyToWebView(ctx context.Context, wv *webkit.WebView) {
188	if sm == nil {
189		return
190	}
191	if wv == nil {
192		return
193	}
194
195	// Apply to the existing settings object attached to the WebView
196	existingSettings := wv.GetSettings()
197	if existingSettings != nil {
198		payload := sm.current()
199		sm.applySettings(ctx, existingSettings, payload)
200	}
201}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close