Files

118 lines
3.8 KiB
Go

// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package preferences
/*
#include <stdlib.h>
#include "native.h"
*/
import "C"
import (
"fmt"
"git.stormux.org/storm/cthulhu/internal/interaction"
"git.stormux.org/storm/cthulhu/internal/tentaclewire"
"unsafe"
)
func extension_page_key(page ExtensionPage) string { return page.Session + "/" + page.ID }
// GTK owns native focus. Refreshes keep unchanged widgets and their unapplied
// drafts, and move focus to the notebook before removing a revoked page.
func (session *uiSession) set_extension_pages(pages []ExtensionPage) error {
selected := C.GoString(C.prefs_extension_selected())
ids := map[string]bool{}
for _, page := range pages {
key := extension_page_key(page)
if page.Session == "" || ids[key] {
return fmt.Errorf("invalid extension page identity")
}
ids[key] = true
if err := tentaclewire.ValidateExtensions(tentaclewire.Extensions{Pages: []tentaclewire.PreferencePage{page.PreferencePage}}); err != nil {
return err
}
}
keep := map[string]bool{}
for _, previous := range session.extensionPages {
key := extension_page_key(previous)
for _, page := range pages {
if extension_page_key(page) == key && page.Revision == previous.Revision {
keep[key] = true
break
}
}
if !keep[key] {
cKey := C.CString(key)
C.prefs_extension_remove(cKey)
C.free(unsafe.Pointer(cKey))
}
}
for _, page := range pages {
key := extension_page_key(page)
if keep[key] {
continue
}
cKey, title := C.CString(key), C.CString(page.Title)
C.prefs_extension_add(cKey, title)
C.free(unsafe.Pointer(title))
for row, element := range page.Elements {
id, label := C.CString(element.ID), C.CString(element.Label)
C.prefs_extension_control(cKey, id, label, C.int(element.Kind), C.int(row), C.int(element.MaxLength), boolean(element.Disabled))
C.free(unsafe.Pointer(label))
for _, option := range element.Items {
optionID, optionLabel := C.CString(option.ID), C.CString(option.Label)
C.prefs_extension_option(cKey, id, optionID, optionLabel, boolean(option.Disabled))
C.free(unsafe.Pointer(optionID))
C.free(unsafe.Pointer(optionLabel))
}
value := page.Values[element.ID]
text := value.Text
if element.Kind == interaction.List {
text = value.Selected
}
cText := C.CString(text)
C.prefs_extension_set(cKey, id, C.int(element.Kind), cText, boolean(value.Checked))
C.free(unsafe.Pointer(cText))
C.free(unsafe.Pointer(id))
}
C.free(unsafe.Pointer(cKey))
}
session.extensionPages = pages
if selected != "" {
key := C.CString(selected)
C.prefs_extension_select(key)
C.free(unsafe.Pointer(key))
}
return nil
}
func (session *uiSession) extension_drafts() ([]PageDraft, error) {
var drafts []PageDraft
for _, page := range session.extensionPages {
values := map[string]interaction.Value{}
key := C.CString(extension_page_key(page))
for _, element := range page.Elements {
id := C.CString(element.ID)
value := interaction.Value{}
switch element.Kind {
case interaction.List:
value.Selected = C.GoString(C.prefs_extension_text(key, id, C.int(element.Kind)))
case interaction.Entry:
value.Text = C.GoString(C.prefs_extension_text(key, id, C.int(element.Kind)))
case interaction.CheckBox:
value.Checked = C.prefs_extension_checked(key, id) != 0
}
C.free(unsafe.Pointer(id))
values[element.ID] = value
}
C.free(unsafe.Pointer(key))
declaration := page.PreferencePage
declaration.Values = values
if err := tentaclewire.ValidateExtensions(tentaclewire.Extensions{Pages: []tentaclewire.PreferencePage{declaration}}); err != nil {
return nil, fmt.Errorf("Check the values on %s: %w", page.Title, err)
}
drafts = append(drafts, PageDraft{Session: page.Session, ID: page.ID, Revision: page.Revision, Values: values})
}
return drafts, nil
}