Skip to content

Commit da32dd8

Browse files
Remove app mode auto-toggle for small viewports (kernel#155)
## Summary - Removes the `ensureAppMode` logic that automatically added `--app` flag and forced Chromium restarts when switching to viewports below 500px width - The patched kernel-browser removes Chromium's minimum width constraint, making this workaround unnecessary - Removes `RemoveFlagsByPrefix`, `HasFlagWithPrefix`, `appModeURL` constant, and associated tests ## Test plan - [x] Verified locally with patched Chromium (v145) — 390x844 viewport works without `--app` mode or restart - [ ] CI passes Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Removes a conditional flag-mutation path during display resizing; behavior change is localized and simplifies the restart logic, with minimal impact outside small-viewport scenarios. > > **Overview** > Removes the *small-viewport “app mode” workaround* in `PatchDisplay`: resolution changes no longer auto-add/remove the Chromium `--app` flag (and no longer force a restart solely due to that toggle). > > Cleans up the now-unused support code by deleting `appModeURL`, `ensureAppMode`, and the `chromiumflags` helpers `RemoveFlagsByPrefix`/`HasFlagWithPrefix` along with their unit tests; `chromiumFlagsPath` is kept as a single constant for flag-file operations. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c47197f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent c8a53d5 commit da32dd8

4 files changed

Lines changed: 2 additions & 158 deletions

File tree

server/cmd/api/api/chromium.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,8 @@ import (
2121

2222
var nameRegex = regexp.MustCompile(`^[A-Za-z0-9._-]{1,255}$`)
2323

24-
const (
25-
// chromiumFlagsPath is the runtime flags file read by the chromium-launcher at startup.
26-
chromiumFlagsPath = "/chromium/flags"
27-
28-
// appModeURL is the URL loaded in --app mode for small viewports. Keep in
29-
// sync with "NewTabPageLocation" in shared/chromium-policies/managed/policy.json.
30-
appModeURL = "https://start.duckduckgo.com"
31-
)
24+
// chromiumFlagsPath is the runtime flags file read by the chromium-launcher at startup.
25+
const chromiumFlagsPath = "/chromium/flags"
3226

3327
// UploadExtensionsAndRestart handles multipart upload of one or more extension zips, extracts
3428
// them under /home/kernel/extensions/<name>, writes /chromium/flags to enable them, restarts

server/cmd/api/api/display.go

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"strings"
1111

1212
nekooapi "github.com/m1k1o/neko/server/lib/oapi"
13-
"github.com/onkernel/kernel-images/server/lib/chromiumflags"
1413
"github.com/onkernel/kernel-images/server/lib/logger"
1514
oapi "github.com/onkernel/kernel-images/server/lib/oapi"
1615
)
@@ -89,21 +88,6 @@ func (s *ApiService) PatchDisplay(ctx context.Context, req oapi.PatchDisplayRequ
8988
restartChrome = *req.Body.RestartChromium
9089
}
9190

92-
// App mode: Chromium's --app flag removes the tab bar and toolbar chrome,
93-
// allowing the window to resize below the normal ~500px minimum width
94-
// and ~200px minimum height.
95-
// We automatically toggle this based on the requested viewport dimensions.
96-
const appModeWidthThreshold = 500
97-
const appModeHeightThreshold = 200
98-
needsAppMode := width < appModeWidthThreshold || height < appModeHeightThreshold
99-
if toggled, err := s.ensureAppMode(ctx, needsAppMode); err != nil {
100-
log.Error("failed to toggle app mode", "error", err)
101-
// Non-fatal: continue with the resize even if app mode toggle fails.
102-
} else if toggled {
103-
// App mode changed — force a chromium restart so it picks up the new flags.
104-
restartChrome = true
105-
}
106-
10791
// Route to appropriate resolution change handler
10892
if displayMode == "xorg" {
10993
if s.isNekoEnabled() {
@@ -407,54 +391,3 @@ func (s *ApiService) setResolutionViaNeko(ctx context.Context, width, height, re
407391
return nil
408392
}
409393

410-
// ensureAppMode adds or removes the --app flag from the Chromium runtime flags
411-
// file. When enabling, any existing --app flag is removed first so the URL is
412-
// always exactly appModeURL (defined in chromium.go). It returns (true, nil)
413-
// when the flag state was changed (meaning Chromium needs a restart), or
414-
// (false, nil) when no change was needed.
415-
func (s *ApiService) ensureAppMode(ctx context.Context, enable bool) (toggled bool, err error) {
416-
log := logger.FromContext(ctx)
417-
const appPrefix = "--app"
418-
wantFlag := appPrefix + "=" + appModeURL
419-
420-
existing, err := chromiumflags.ReadOptionalFlagFile(chromiumFlagsPath)
421-
if err != nil {
422-
return false, fmt.Errorf("failed to read flags file: %w", err)
423-
}
424-
425-
// Always strip any --app/--app=... flags so we can compare cleanly.
426-
stripped := chromiumflags.RemoveFlagsByPrefix(existing, appPrefix)
427-
428-
if enable {
429-
updated := append(stripped, wantFlag)
430-
// If the exact flag was already present and nothing else changed, no-op.
431-
if chromiumflags.HasFlagWithPrefix(existing, appPrefix) && len(updated) == len(existing) {
432-
// Check the existing flag is the exact one we want.
433-
for _, tok := range existing {
434-
if tok == wantFlag {
435-
log.Info("app mode already enabled with correct URL, no change needed")
436-
return false, nil
437-
}
438-
}
439-
}
440-
log.Info("enabling app mode for small viewport", "flag", wantFlag)
441-
if err := writeChromiumFlags(updated); err != nil {
442-
return false, err
443-
}
444-
log.Info("app mode toggled", "enabled", true, "flags", updated)
445-
return true, nil
446-
}
447-
448-
// Disabling: if nothing was stripped, already disabled.
449-
if len(stripped) == len(existing) {
450-
log.Info("app mode already disabled, no change needed")
451-
return false, nil
452-
}
453-
454-
log.Info("disabling app mode for normal viewport")
455-
if err := writeChromiumFlags(stripped); err != nil {
456-
return false, err
457-
}
458-
log.Info("app mode toggled", "enabled", false, "flags", stripped)
459-
return true, nil
460-
}

server/lib/chromiumflags/chromiumflags.go

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -224,31 +224,6 @@ func MergeExtensionPath(args []string, extPath string) []string {
224224
return result
225225
}
226226

227-
// RemoveFlagsByPrefix returns a new slice with any tokens that match the given
228-
// prefix removed. For example, prefix "--app" removes "--app", "--app=about:blank", etc.
229-
// It does NOT match longer flag names that merely share the prefix
230-
// (e.g. "--app" will not match "--application-name").
231-
func RemoveFlagsByPrefix(tokens []string, prefix string) []string {
232-
out := make([]string, 0, len(tokens))
233-
for _, tok := range tokens {
234-
if tok == prefix || strings.HasPrefix(tok, prefix+"=") {
235-
continue
236-
}
237-
out = append(out, tok)
238-
}
239-
return out
240-
}
241-
242-
// HasFlagWithPrefix returns true if any token equals prefix or starts with prefix + "=".
243-
func HasFlagWithPrefix(tokens []string, prefix string) bool {
244-
for _, tok := range tokens {
245-
if tok == prefix || strings.HasPrefix(tok, prefix+"=") {
246-
return true
247-
}
248-
}
249-
return false
250-
}
251-
252227
// WriteFlagFile writes the provided tokens to the given path as JSON in the
253228
// form: { "flags": ["--foo", "--bar=1"] } with file mode 0644.
254229
// The function creates or truncates the file.

server/lib/chromiumflags/chromiumflags_test.go

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"reflect"
88
"strings"
99
"testing"
10-
11-
"github.com/stretchr/testify/assert"
1210
)
1311

1412
func TestParseFlags(t *testing.T) {
@@ -216,62 +214,6 @@ func TestWriteFlagFileAndReadBack(t *testing.T) {
216214

217215
// TestWriteFlagFileFromString removed: callers should use WriteFlagFile with tokens.
218216

219-
func TestRemoveFlagsByPrefix(t *testing.T) {
220-
tests := []struct {
221-
name string
222-
tokens []string
223-
prefix string
224-
want []string
225-
}{
226-
{
227-
name: "remove exact match",
228-
tokens: []string{"--foo", "--app", "--bar"},
229-
prefix: "--app",
230-
want: []string{"--foo", "--bar"},
231-
},
232-
{
233-
name: "remove prefix=value match",
234-
tokens: []string{"--foo", "--app=about:blank", "--bar"},
235-
prefix: "--app",
236-
want: []string{"--foo", "--bar"},
237-
},
238-
{
239-
name: "does not remove longer flag names",
240-
tokens: []string{"--foo", "--application-name=test", "--app=about:blank"},
241-
prefix: "--app",
242-
want: []string{"--foo", "--application-name=test"},
243-
},
244-
{
245-
name: "nothing to remove",
246-
tokens: []string{"--foo", "--bar"},
247-
prefix: "--app",
248-
want: []string{"--foo", "--bar"},
249-
},
250-
{
251-
name: "empty input",
252-
tokens: []string{},
253-
prefix: "--app",
254-
want: []string{},
255-
},
256-
}
257-
for _, tt := range tests {
258-
t.Run(tt.name, func(t *testing.T) {
259-
got := RemoveFlagsByPrefix(tt.tokens, tt.prefix)
260-
if !reflect.DeepEqual(got, tt.want) {
261-
t.Errorf("RemoveFlagsByPrefix() = %#v, want %#v", got, tt.want)
262-
}
263-
})
264-
}
265-
}
266-
267-
func TestHasFlagWithPrefix(t *testing.T) {
268-
assert.True(t, HasFlagWithPrefix([]string{"--app=about:blank", "--foo"}, "--app"))
269-
assert.True(t, HasFlagWithPrefix([]string{"--foo", "--app"}, "--app"))
270-
assert.False(t, HasFlagWithPrefix([]string{"--application-name=test"}, "--app"))
271-
assert.False(t, HasFlagWithPrefix([]string{"--foo", "--bar"}, "--app"))
272-
assert.False(t, HasFlagWithPrefix([]string{}, "--app"))
273-
}
274-
275217
func TestMergeFlags(t *testing.T) {
276218
tests := []struct {
277219
name string

0 commit comments

Comments
 (0)