v0.14.1 0da30ba

favicon_helpers.go RawHistoryFolder

1package webkit
2
3/*
4#cgo pkg-config: webkitgtk-6.0
5#include <webkit/webkit.h>
6*/
7import "C"
8
9import (
10	"context"
11	"crypto/md5"
12	"fmt"
13	"net/url"
14	"runtime"
15	"unsafe"
16
17	webkit "github.com/diamondburned/gotk4-webkitgtk/pkg/webkit/v6"
18	"github.com/diamondburned/gotk4/pkg/core/gerror"
19	coreglib "github.com/diamondburned/gotk4/pkg/core/glib"
20	"github.com/diamondburned/gotk4/pkg/gdk/v4"
21	"github.com/diamondburned/gotk4/pkg/gdkpixbuf/v2"
22	gio "github.com/diamondburned/gotk4/pkg/gio/v2"
23	"github.com/diamondburned/gotk4/pkg/glib/v2"
24)
25
26// GdkTexture is an alias for gotk4's Texture type
27type GdkTexture = gdk.Texture
28
29// FaviconDatabase is an alias for WebKit's FaviconDatabase
30type FaviconDatabase = webkit.FaviconDatabase
31
32// SaveTextureAsPNG saves a GdkTexture as a PNG file at target size
33// WebKit provides GdkTexture which can be any format (ICO, PNG, JPEG, SVG)
34// This function normalizes everything to PNG at the target size (32x32)
35func SaveTextureAsPNG(texture *gdk.Texture, path string, targetSize int) error {
36	if texture == nil {
37		return fmt.Errorf("texture cannot be nil")
38	}
39
40	width := texture.Width()
41	height := texture.Height()
42
43	// If texture needs scaling, create scaled version
44	if width != targetSize || height != targetSize {
45		texture = ScaleTexture(texture, targetSize, targetSize)
46		if texture == nil {
47			return fmt.Errorf("failed to scale texture")
48		}
49	}
50
51	// Save texture as PNG using built-in method
52	if !texture.SaveToPNG(path) {
53		return fmt.Errorf("failed to save PNG to %s", path)
54	}
55
56	return nil
57}
58
59// ScaleTexture scales a texture to the target size using GdkPixbuf
60// Uses high-quality bilinear interpolation
61func ScaleTexture(texture *gdk.Texture, targetWidth, targetHeight int) *gdk.Texture {
62	if texture == nil {
63		return nil
64	}
65
66	// Get PNG bytes from texture
67	pngBytes := texture.SaveToPNGBytes()
68	if pngBytes == nil {
69		return nil
70	}
71
72	// Load as pixbuf using memory input stream
73	ctx := context.Background()
74	stream := gio.NewMemoryInputStreamFromBytes(pngBytes)
75	pixbuf, err := gdkpixbuf.NewPixbufFromStream(ctx, stream)
76	if err != nil || pixbuf == nil {
77		return nil
78	}
79
80	// Scale pixbuf
81	scaled := pixbuf.ScaleSimple(targetWidth, targetHeight, gdkpixbuf.InterpBilinear)
82	if scaled == nil {
83		return nil
84	}
85
86	// Convert back to texture
87	return gdk.NewTextureForPixbuf(scaled)
88}
89
90// HashURL generates an MD5 hash of a URL for filename generation
91func HashURL(pageURL string) []byte {
92	hash := md5.Sum([]byte(pageURL))
93	return hash[:]
94}
95
96// ParseURL is a convenience wrapper around url.Parse
97func ParseURL(rawURL string) (*url.URL, error) {
98	return url.Parse(rawURL)
99}
100
101// FaviconFinishSafe mirrors gotk4's FaviconFinish but guards against NULL returns.
102func FaviconFinishSafe(database *webkit.FaviconDatabase, result gio.AsyncResulter) (*gdk.Texture, error) {
103	if database == nil || result == nil {
104		return nil, fmt.Errorf("favicon finish: invalid arguments")
105	}
106
107	cDatabase := (*C.WebKitFaviconDatabase)(unsafe.Pointer(glib.BaseObject(database).Native()))
108	cResult := (*C.GAsyncResult)(unsafe.Pointer(glib.BaseObject(result).Native()))
109
110	var cErr *C.GError
111	cTexture := C.webkit_favicon_database_get_favicon_finish(cDatabase, cResult, &cErr)
112	runtime.KeepAlive(database)
113	runtime.KeepAlive(result)
114
115	if cErr != nil {
116		err := gerror.Take(unsafe.Pointer(cErr))
117		return nil, err
118	}
119	if cTexture == nil {
120		return nil, nil
121	}
122
123	object := coreglib.AssumeOwnership(unsafe.Pointer(cTexture))
124	casted := object.WalkCast(func(obj coreglib.Objector) bool {
125		_, ok := obj.(gdk.Texturer)
126		return ok
127	})
128
129	texturer, ok := casted.(gdk.Texturer)
130	if !ok {
131		return nil, fmt.Errorf("favicon finish: unexpected type %T", casted)
132	}
133
134	texture := gdk.BaseTexture(texturer)
135	if texture == nil {
136		return nil, fmt.Errorf("favicon finish: texture unavailable")
137	}
138
139	return texture, nil
140}
141
142// TextureFromImageBytes creates a texture from raw image bytes.
143// Supported formats depend on the available GdkPixbuf loaders (PNG, SVG, etc.).
144func TextureFromImageBytes(data []byte) (*gdk.Texture, error) {
145	if len(data) == 0 {
146		return nil, fmt.Errorf("image data is empty")
147	}
148
149	// Convert []byte to glib.Bytes for gio API
150	glibBytes := glib.NewBytes(data)
151	stream := gio.NewMemoryInputStreamFromBytes(glibBytes)
152	pixbuf, err := gdkpixbuf.NewPixbufFromStream(context.Background(), stream)
153	if err != nil {
154		return nil, fmt.Errorf("load pixbuf: %w", err)
155	}
156
157	texture := gdk.NewTextureForPixbuf(pixbuf)
158	if texture == nil {
159		return nil, fmt.Errorf("create texture from pixbuf failed")
160	}
161
162	return texture, nil
163}

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