refactor: minor API and type improvements
- Add new type definitions for enhanced GUI functionality - Update API scheme handling with better error management - Refine CLI browse command with improved argument processing - Enhance keyboard handling in WebKit CGO bindings
- commit
- 81b4f58dc379925d2841c48f77f1febf772484e4
- author
- bamen · · 2025-09-23 19:03 UTC
- committer
- bamen · · 2025-09-23 19:13 UTC
- parent
- 266137a
- signature
- unsigned
4 files · +35 -6
M gui/src/lib/types.ts +6 -0
| @@ -1,5 +1,10 @@ | |||
| 1 | 1 | import type { HistoryEntry, SearchShortcut } from "../types/generated.js"; | |
| 2 | 2 | ||
| 3 | + | type ThemeManagerAPI = { | |
| 4 | + | setUserPreference: (theme: "light" | "dark") => void; | |
| 5 | + | getCurrentTheme: () => "light" | "dark"; | |
| 6 | + | }; | |
| 7 | + | ||
| 3 | 8 | // Global window API types for browser integration | |
| 4 | 9 | declare global { | |
| 5 | 10 | interface Window { | |
| @@ -17,6 +22,7 @@ declare global { | |||
| 17 | 22 | // Theme integration | |
| 18 | 23 | __dumber_initial_theme?: string; | |
| 19 | 24 | __dumber_setTheme?: (theme: "light" | "dark") => void; | |
| 25 | + | __dumber_color_scheme_manager?: ThemeManagerAPI; | |
| 20 | 26 | ||
| 21 | 27 | // History callbacks | |
| 22 | 28 | __dumber_history_recent?: (data: HistoryEntry[]) => void; | |
| @@ -1,5 +1,10 @@ | |||||
| 1 | import type { HistoryEntry, SearchShortcut } from "../types/generated.js"; | 1 | import type { HistoryEntry, SearchShortcut } from "../types/generated.js"; | ||
| 2 | 2 | ||||
| 3 | + | type ThemeManagerAPI = { | |||
| 4 | + | setUserPreference: (theme: "light" | "dark") => void; | |||
| 5 | + | getCurrentTheme: () => "light" | "dark"; | |||
| 6 | + | }; | |||
| 7 | + | ||||
| 3 | // Global window API types for browser integration | 8 | // Global window API types for browser integration | ||
| 4 | declare global { | 9 | declare global { | ||
| 5 | interface Window { | 10 | interface Window { | ||
| @@ -17,6 +22,7 @@ declare global { | |||||
| 17 | // Theme integration | 22 | // Theme integration | ||
| 18 | __dumber_initial_theme?: string; | 23 | __dumber_initial_theme?: string; | ||
| 19 | __dumber_setTheme?: (theme: "light" | "dark") => void; | 24 | __dumber_setTheme?: (theme: "light" | "dark") => void; | ||
| 25 | + | __dumber_color_scheme_manager?: ThemeManagerAPI; | |||
| 20 | 26 | ||||
| 21 | // History callbacks | 27 | // History callbacks | ||
| 22 | __dumber_history_recent?: (data: HistoryEntry[]) => void; | 28 | __dumber_history_recent?: (data: HistoryEntry[]) => void; | ||
M internal/app/api/scheme.go +4 -4
| @@ -74,12 +74,12 @@ func (s *SchemeHandler) handleAsset(u *neturl.URL) (string, []byte, bool) { | |||
| 74 | 74 | } | |
| 75 | 75 | } | |
| 76 | 76 | ||
| 77 | - | // Special-case homepage favicon: map .ico request to embedded SVG file | |
| 77 | + | // Special-case homepage favicon: map .ico request to embedded PNG file | |
| 78 | 78 | if (u.Host == constants.HomepagePath || u.Opaque == constants.HomepagePath) && strings.EqualFold(rel, "favicon.ico") { | |
| 79 | - | log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.svg", rel, u.Host, u.Path) | |
| 80 | - | data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.svg"))) | |
| 79 | + | log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.png", rel, u.Host, u.Path) | |
| 80 | + | data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.png"))) | |
| 81 | 81 | if rerr == nil { | |
| 82 | - | return "image/svg+xml", data, true | |
| 82 | + | return "image/png", data, true | |
| 83 | 83 | } | |
| 84 | 84 | } | |
| 85 | 85 | ||
| @@ -74,12 +74,12 @@ func (s *SchemeHandler) handleAsset(u *neturl.URL) (string, []byte, bool) { | |||||
| 74 | } | 74 | } | ||
| 75 | } | 75 | } | ||
| 76 | 76 | ||||
| 77 | - | // Special-case homepage favicon: map .ico request to embedded SVG file | 77 | + | // Special-case homepage favicon: map .ico request to embedded PNG file |
| 78 | if (u.Host == constants.HomepagePath || u.Opaque == constants.HomepagePath) && strings.EqualFold(rel, "favicon.ico") { | 78 | if (u.Host == constants.HomepagePath || u.Opaque == constants.HomepagePath) && strings.EqualFold(rel, "favicon.ico") { | ||
| 79 | - | log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.svg", rel, u.Host, u.Path) | 79 | + | log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.png", rel, u.Host, u.Path) |
| 80 | - | data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.svg"))) | 80 | + | data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.png"))) |
| 81 | if rerr == nil { | 81 | if rerr == nil { | ||
| 82 | - | return "image/svg+xml", data, true | 82 | + | return "image/png", data, true |
| 83 | } | 83 | } | ||
| 84 | } | 84 | } | ||
| 85 | 85 | ||||
M internal/cli/browse.go +6 -2
| @@ -136,8 +136,12 @@ func openURLWithConfig(url string, cfg *config.Config) error { | |||
| 136 | 136 | return nil | |
| 137 | 137 | } | |
| 138 | 138 | ||
| 139 | - | // updateFavicon fetches and stores favicon URL for a given page URL | |
| 139 | + | // updateFavicon is now deprecated in favor of WebKit's native favicon API | |
| 140 | + | // When using the built-in browser, WebKit automatically handles favicon detection | |
| 141 | + | // This function is kept for CLI compatibility but may use fallback behavior | |
| 140 | 142 | func updateFavicon(ctx context.Context, cli *CLI, pageURL string) { | |
| 143 | + | // For CLI usage (non-GUI), we still use the fallback method | |
| 144 | + | // The GUI browser handles favicons through WebKit signals | |
| 141 | 145 | parsedURL, err := url.Parse(pageURL) | |
| 142 | 146 | if err != nil { | |
| 143 | 147 | return // Silently fail for invalid URLs | |
| @@ -151,7 +155,7 @@ func updateFavicon(ctx context.Context, cli *CLI, pageURL string) { | |||
| 151 | 155 | return | |
| 152 | 156 | } | |
| 153 | 157 | ||
| 154 | - | // Standard favicon location | |
| 158 | + | // Standard favicon location (fallback) | |
| 155 | 159 | faviconURL := fmt.Sprintf("%s://%s/favicon.ico", parsedURL.Scheme, parsedURL.Host) | |
| 156 | 160 | ||
| 157 | 161 | // Update in database using the new sqlc-generated method | |
| @@ -136,8 +136,12 @@ func openURLWithConfig(url string, cfg *config.Config) error { | |||||
| 136 | return nil | 136 | return nil | ||
| 137 | } | 137 | } | ||
| 138 | 138 | ||||
| 139 | - | // updateFavicon fetches and stores favicon URL for a given page URL | 139 | + | // updateFavicon is now deprecated in favor of WebKit's native favicon API |
| 140 | + | // When using the built-in browser, WebKit automatically handles favicon detection | |||
| 141 | + | // This function is kept for CLI compatibility but may use fallback behavior | |||
| 140 | func updateFavicon(ctx context.Context, cli *CLI, pageURL string) { | 142 | func updateFavicon(ctx context.Context, cli *CLI, pageURL string) { | ||
| 143 | + | // For CLI usage (non-GUI), we still use the fallback method | |||
| 144 | + | // The GUI browser handles favicons through WebKit signals | |||
| 141 | parsedURL, err := url.Parse(pageURL) | 145 | parsedURL, err := url.Parse(pageURL) | ||
| 142 | if err != nil { | 146 | if err != nil { | ||
| 143 | return // Silently fail for invalid URLs | 147 | return // Silently fail for invalid URLs | ||
| @@ -151,7 +155,7 @@ func updateFavicon(ctx context.Context, cli *CLI, pageURL string) { | |||||
| 151 | return | 155 | return | ||
| 152 | } | 156 | } | ||
| 153 | 157 | ||||
| 154 | - | // Standard favicon location | 158 | + | // Standard favicon location (fallback) |
| 155 | faviconURL := fmt.Sprintf("%s://%s/favicon.ico", parsedURL.Scheme, parsedURL.Host) | 159 | faviconURL := fmt.Sprintf("%s://%s/favicon.ico", parsedURL.Scheme, parsedURL.Host) | ||
| 156 | 160 | ||||
| 157 | // Update in database using the new sqlc-generated method | 161 | // Update in database using the new sqlc-generated method | ||
M pkg/webkit/keyboard_cgo.go +19 -0
| @@ -508,6 +508,25 @@ func goOnURIChanged(id C.ulong, curi *C.char) { | |||
| 508 | 508 | vw.dispatchURIChanged(uri) | |
| 509 | 509 | } | |
| 510 | 510 | ||
| 511 | + | //export goOnFaviconURIChanged | |
| 512 | + | func goOnFaviconURIChanged(id C.ulong, pageURI *C.char, faviconURI *C.char) { | |
| 513 | + | uid := uintptr(id) | |
| 514 | + | pageURLStr := C.GoString(pageURI) | |
| 515 | + | faviconURLStr := C.GoString(faviconURI) | |
| 516 | + | ||
| 517 | + | log.Printf("[favicon] WebKit favicon URI changed for WebView ID %d - page: %s, favicon: %s", uid, pageURLStr, faviconURLStr) | |
| 518 | + | ||
| 519 | + | regMu.RLock() | |
| 520 | + | vw := viewByID[uid] | |
| 521 | + | regMu.RUnlock() | |
| 522 | + | if vw == nil { | |
| 523 | + | log.Printf("[favicon] WebView not found for ID %d", uid) | |
| 524 | + | return | |
| 525 | + | } | |
| 526 | + | ||
| 527 | + | vw.dispatchFaviconURIChanged(pageURLStr, faviconURLStr) | |
| 528 | + | } | |
| 529 | + | ||
| 511 | 530 | //export goHandleNewWindowPolicy | |
| 512 | 531 | func goHandleNewWindowPolicy(id C.ulong, curi *C.char, navType C.int, cframeName *C.char, isUserGesture C.gboolean, modifiers C.guint, mouseButton C.guint) C.gboolean { | |
| 513 | 532 | uid := uintptr(id) | |
| @@ -508,6 +508,25 @@ func goOnURIChanged(id C.ulong, curi *C.char) { | |||||
| 508 | vw.dispatchURIChanged(uri) | 508 | vw.dispatchURIChanged(uri) | ||
| 509 | } | 509 | } | ||
| 510 | 510 | ||||
| 511 | + | //export goOnFaviconURIChanged | |||
| 512 | + | func goOnFaviconURIChanged(id C.ulong, pageURI *C.char, faviconURI *C.char) { | |||
| 513 | + | uid := uintptr(id) | |||
| 514 | + | pageURLStr := C.GoString(pageURI) | |||
| 515 | + | faviconURLStr := C.GoString(faviconURI) | |||
| 516 | + | ||||
| 517 | + | log.Printf("[favicon] WebKit favicon URI changed for WebView ID %d - page: %s, favicon: %s", uid, pageURLStr, faviconURLStr) | |||
| 518 | + | ||||
| 519 | + | regMu.RLock() | |||
| 520 | + | vw := viewByID[uid] | |||
| 521 | + | regMu.RUnlock() | |||
| 522 | + | if vw == nil { | |||
| 523 | + | log.Printf("[favicon] WebView not found for ID %d", uid) | |||
| 524 | + | return | |||
| 525 | + | } | |||
| 526 | + | ||||
| 527 | + | vw.dispatchFaviconURIChanged(pageURLStr, faviconURLStr) | |||
| 528 | + | } | |||
| 529 | + | ||||
| 511 | //export goHandleNewWindowPolicy | 530 | //export goHandleNewWindowPolicy | ||
| 512 | func goHandleNewWindowPolicy(id C.ulong, curi *C.char, navType C.int, cframeName *C.char, isUserGesture C.gboolean, modifiers C.guint, mouseButton C.guint) C.gboolean { | 531 | func goHandleNewWindowPolicy(id C.ulong, curi *C.char, navType C.int, cframeName *C.char, isUserGesture C.gboolean, modifiers C.guint, mouseButton C.guint) C.gboolean { | ||
| 513 | uid := uintptr(id) | 532 | uid := uintptr(id) | ||