Bring in goodies from testing.
# Conflicts: # docs/testing/wine-proton.md
This commit is contained in:
commit
3026bc55c2
54 files changed
+2615
-918
No files matched your search
@@ -2,6 +2,22 @@
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#include <gtk/gtk.h>
|
||||
// Shared action IDs for the native callbacks and Go preferences dispatcher.
|
||||
// Value 10 is reserved; preserve the existing wire values.
|
||||
enum {
|
||||
PREFS_TENTACLE_REPOSITORY_ADD = 9,
|
||||
PREFS_TENTACLE_TOGGLE = 11,
|
||||
PREFS_TENTACLE_REPOSITORY_REMOVE = 12,
|
||||
PREFS_TENTACLE_RETRY = 13,
|
||||
PREFS_TENTACLE_REMOVE = 14,
|
||||
PREFS_TENTACLE_REFRESH = 15,
|
||||
PREFS_TENTACLE_SELECT = 16,
|
||||
PREFS_TENTACLE_REPOSITORY_SELECT = 17,
|
||||
PREFS_TENTACLE_REPOSITORY_REFRESH = 18,
|
||||
PREFS_TENTACLE_INSTALL = 19,
|
||||
PREFS_TENTACLE_SETTINGS = 20,
|
||||
PREFS_TENTACLE_UPDATE = 21,
|
||||
};
|
||||
int prefs_init(const char *xml);
|
||||
void prefs_set_application(const char *name);
|
||||
void prefs_iterate(void);
|
||||
|
||||
@@ -22,7 +22,7 @@ static void name_toggle_cells(void) {
|
||||
}
|
||||
static void tentacle_selected(GtkTreeSelection *selection, gpointer data) {
|
||||
(void)selection; (void)data;
|
||||
if (!updating) prefs_set_action(16);
|
||||
if (!updating) prefs_set_action(PREFS_TENTACLE_SELECT);
|
||||
}
|
||||
static void tentacle_clicked(GtkButton *button, gpointer data) {
|
||||
(void)button;
|
||||
@@ -36,12 +36,12 @@ static void tentacle_toggled(GtkCellRendererToggle *renderer, gchar *pathString,
|
||||
gtk_tree_path_free(path);
|
||||
// The accepted backend snapshot owns the check state; never check
|
||||
// optimistically before persistence or after an operation has failed.
|
||||
prefs_set_action(11);
|
||||
prefs_set_action(PREFS_TENTACLE_TOGGLE);
|
||||
}
|
||||
static gboolean tentacle_key(GtkWidget *widget, GdkEventKey *event, gpointer data) {
|
||||
(void)widget; (void)data;
|
||||
if (event->keyval != GDK_KEY_space && event->keyval != GDK_KEY_KP_Space) return FALSE;
|
||||
prefs_set_action(11);
|
||||
prefs_set_action(PREFS_TENTACLE_TOGGLE);
|
||||
return TRUE;
|
||||
}
|
||||
static void repository_switched(GtkNotebook *notebook, GtkWidget *page, guint index, gpointer data) {
|
||||
@@ -54,7 +54,7 @@ static void repository_switched(GtkNotebook *notebook, GtkWidget *page, guint in
|
||||
gtk_container_add(GTK_CONTAINER(page), scroll);
|
||||
g_object_unref(scroll);
|
||||
}
|
||||
if (!updating) prefs_set_action(17);
|
||||
if (!updating) prefs_set_action(PREFS_TENTACLE_REPOSITORY_SELECT);
|
||||
}
|
||||
void prefs_init_tentacles(void) {
|
||||
updating = FALSE;
|
||||
@@ -74,9 +74,15 @@ void prefs_init_tentacles(void) {
|
||||
g_signal_connect(tree, "key-press-event", G_CALLBACK(tentacle_key), NULL);
|
||||
g_signal_connect(prefs_widget("tentacleRepositories"), "switch-page", G_CALLBACK(repository_switched), NULL);
|
||||
const struct { const char *id; int action; } buttons[] = {
|
||||
{"tentacleNew", 9}, {"tentacleRetry", 13}, {"tentacleRemove", 14},
|
||||
{"tentacleRefresh", 15}, {"tentacleRepositoryRemove", 12}, {"tentacleRepositoryRefresh", 18},
|
||||
{"tentacleInstall", 19}, {"tentacleUpdate", 21}, {"tentacleSettings", 20},
|
||||
{"tentacleNew", PREFS_TENTACLE_REPOSITORY_ADD},
|
||||
{"tentacleRetry", PREFS_TENTACLE_RETRY},
|
||||
{"tentacleRemove", PREFS_TENTACLE_REMOVE},
|
||||
{"tentacleRefresh", PREFS_TENTACLE_REFRESH},
|
||||
{"tentacleRepositoryRemove", PREFS_TENTACLE_REPOSITORY_REMOVE},
|
||||
{"tentacleRepositoryRefresh", PREFS_TENTACLE_REPOSITORY_REFRESH},
|
||||
{"tentacleInstall", PREFS_TENTACLE_INSTALL},
|
||||
{"tentacleUpdate", PREFS_TENTACLE_UPDATE},
|
||||
{"tentacleSettings", PREFS_TENTACLE_SETTINGS},
|
||||
};
|
||||
for (unsigned i = 0; i < G_N_ELEMENTS(buttons); i++)
|
||||
g_signal_connect(prefs_widget(buttons[i].id), "clicked", G_CALLBACK(tentacle_clicked), GINT_TO_POINTER(buttons[i].action));
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package preferences
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include "native.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/tentacle"
|
||||
)
|
||||
|
||||
func (page *tentaclePage) action(action int) (*tentacle.ManagementRequest, error) {
|
||||
if action == C.PREFS_TENTACLE_SELECT {
|
||||
if selected := page.selected(); selected != nil {
|
||||
page.selectedKey = selected.key
|
||||
}
|
||||
page.controls()
|
||||
return nil, nil
|
||||
}
|
||||
if action == C.PREFS_TENTACLE_REPOSITORY_SELECT {
|
||||
page.render()
|
||||
return nil, nil
|
||||
}
|
||||
if action == C.PREFS_TENTACLE_REFRESH {
|
||||
return &tentacle.ManagementRequest{Action: "list"}, nil
|
||||
}
|
||||
if page.snapshot == nil || page.snapshot.Suppressed || page.snapshot.Message != "" {
|
||||
message := "Tentacle management is unavailable for this run."
|
||||
if page.snapshot != nil && page.snapshot.Message != "" {
|
||||
message = page.snapshot.Message
|
||||
}
|
||||
return nil, errors.New(message)
|
||||
}
|
||||
if action == C.PREFS_TENTACLE_REPOSITORY_ADD {
|
||||
id := C.CString("tentacleRepositoryURL")
|
||||
origin, err := tentacle.RepositoryURL(C.GoString(C.prefs_entry_get(id)))
|
||||
C.free(unsafe.Pointer(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: "repository-add", URL: origin}, nil
|
||||
}
|
||||
if action == C.PREFS_TENTACLE_REPOSITORY_REMOVE || action == C.PREFS_TENTACLE_REPOSITORY_REFRESH {
|
||||
origin := page.origin()
|
||||
if origin == "" {
|
||||
return nil, errors.New("Select a repository tab first.")
|
||||
}
|
||||
operation := "repository-remove"
|
||||
if action == C.PREFS_TENTACLE_REPOSITORY_REFRESH {
|
||||
operation = "repository-refresh"
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: operation, URL: origin}, nil
|
||||
}
|
||||
selected := page.selected()
|
||||
if selected == nil {
|
||||
return nil, errors.New("Select a tentacle first.")
|
||||
}
|
||||
page.selectedKey = selected.key
|
||||
if action == C.PREFS_TENTACLE_UPDATE {
|
||||
return page.updatePackage(selected)
|
||||
}
|
||||
if !selected.installed {
|
||||
return page.installPackage(selected, action)
|
||||
}
|
||||
operation := ""
|
||||
switch action {
|
||||
case C.PREFS_TENTACLE_TOGGLE:
|
||||
operation = "enable"
|
||||
if selected.status.Entry.Enabled {
|
||||
operation = "disable"
|
||||
}
|
||||
case C.PREFS_TENTACLE_RETRY:
|
||||
operation = "retry"
|
||||
case C.PREFS_TENTACLE_REMOVE:
|
||||
operation = "remove"
|
||||
case C.PREFS_TENTACLE_SETTINGS:
|
||||
operation = "settings"
|
||||
default:
|
||||
return nil, errors.New("Unknown tentacle action.")
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: operation, ID: selected.status.Entry.ID}, nil
|
||||
}
|
||||
|
||||
func (page *tentaclePage) updatePackage(selected *tentacleRow) (*tentacle.ManagementRequest, error) {
|
||||
if !selected.installed {
|
||||
return nil, errors.New("Install this tentacle first.")
|
||||
}
|
||||
entry := selected.status.Entry
|
||||
for _, update := range page.snapshot.Updates {
|
||||
if update.ID != entry.ID {
|
||||
continue
|
||||
}
|
||||
manifest := findTentacleManifest(page.snapshot, update.RepositoryURL, update.RepositoryID, update.LocalID)
|
||||
if manifest == nil {
|
||||
return nil, errors.New("Updated package manifest is unavailable; refresh the repository before upgrading.")
|
||||
}
|
||||
message := tentacleUpdateConfirmation(entry, update, *manifest)
|
||||
if !confirmTentaclePackage(message, "Update") {
|
||||
return nil, nil
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: "upgrade", ID: update.LocalID, URL: update.RepositoryURL}, nil
|
||||
}
|
||||
return nil, errors.New("No newer version is available for the selected tentacle. Refresh its repository to check again.")
|
||||
}
|
||||
|
||||
func (page *tentaclePage) installPackage(selected *tentacleRow, action int) (*tentacle.ManagementRequest, error) {
|
||||
if action != C.PREFS_TENTACLE_TOGGLE && action != C.PREFS_TENTACLE_INSTALL {
|
||||
return nil, errors.New("Install this tentacle first.")
|
||||
}
|
||||
entry := selected.status.Entry
|
||||
manifest := findTentacleManifest(page.snapshot, entry.Repository, entry.RepositoryID, entry.LocalID)
|
||||
if manifest == nil || len(manifest.Releases) == 0 {
|
||||
return nil, errors.New("No package has been published for this tentacle. Refresh the repository after a release is published.")
|
||||
}
|
||||
operation, label := "install", "Install"
|
||||
if action == C.PREFS_TENTACLE_TOGGLE {
|
||||
operation, label = "install-enable", "Install and enable"
|
||||
}
|
||||
message := tentacleInstallConfirmation(entry, *manifest, label)
|
||||
if !confirmTentaclePackage(message, label) {
|
||||
return nil, nil
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: operation, ID: entry.LocalID, URL: entry.Repository}, nil
|
||||
}
|
||||
|
||||
func confirmTentaclePackage(message, label string) bool {
|
||||
text, button := C.CString(message), C.CString(label)
|
||||
defer C.free(unsafe.Pointer(text))
|
||||
defer C.free(unsafe.Pointer(button))
|
||||
return C.prefs_tentacle_confirm(text, button) != 0
|
||||
}
|
||||
|
||||
// Snapshot repositories have unique identities and local package IDs.
|
||||
func findTentacleManifest(snapshot *tentacle.Snapshot, origin, repositoryID, localID string) *tentacle.Manifest {
|
||||
for _, repository := range snapshot.Repositories {
|
||||
if repository.URL != origin || repository.ID != repositoryID {
|
||||
continue
|
||||
}
|
||||
for index := range repository.Tentacles {
|
||||
if repository.Tentacles[index].ID == localID {
|
||||
return &repository.Tentacles[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package preferences
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/tentacle"
|
||||
)
|
||||
|
||||
func tentacleUpdateCapabilities(entry tentacle.Entry, manifest tentacle.Manifest) string {
|
||||
var previous []string
|
||||
if entry.Presentation {
|
||||
previous = append(previous, "presentation")
|
||||
}
|
||||
if entry.Interaction {
|
||||
previous = append(previous, "interaction")
|
||||
}
|
||||
if entry.ReaderSettings {
|
||||
previous = append(previous, "reader-settings")
|
||||
}
|
||||
if len(previous) == 0 {
|
||||
previous = append(previous, "none")
|
||||
}
|
||||
declared := manifest.Capabilities
|
||||
if len(declared) == 0 {
|
||||
declared = []string{"none"}
|
||||
}
|
||||
return "Current capabilities: " + strings.Join(previous, ", ") +
|
||||
". Repository declares: " + strings.Join(declared, ", ") + "."
|
||||
}
|
||||
|
||||
func tentacleInstallConfirmation(entry tentacle.Entry, manifest tentacle.Manifest, label string) string {
|
||||
permissions := "This tentacle can register reader commands."
|
||||
if slices.Contains(manifest.Capabilities, "presentation") {
|
||||
permissions = "This tentacle can register reader commands and send speech and braille messages."
|
||||
}
|
||||
if slices.Contains(manifest.Capabilities, "interaction") {
|
||||
permissions = "This tentacle can register reader commands, send speech and braille messages, open internal forms, read the focused item and clipboard when invoked, and write clipboard text."
|
||||
}
|
||||
if slices.Contains(manifest.Capabilities, "reader-settings") {
|
||||
permissions += " It can also add preferences pages and quick settings, inspect speech voices, and temporarily change the reader voice configuration."
|
||||
}
|
||||
return fmt.Sprintf("%s %s version %s from %s?\n\n%s\n\nOnly install packages from publishers you trust. Tentacles run with your account's access; resource limits do not protect your files or network.\n\nTentacle management changes take effect immediately.", label, entry.Name, entry.Version, entry.Repository, permissions)
|
||||
}
|
||||
|
||||
func tentacleUpdateConfirmation(entry tentacle.Entry, update tentacle.AvailableUpdate, manifest tentacle.Manifest) string {
|
||||
permissions := tentacleUpdateCapabilities(entry, manifest)
|
||||
return fmt.Sprintf("Update %s from version %s to version %s?\n\n%s\n\nOnly update packages from publishers you trust. Tentacles run with your account's access.\n\nChanges take effect immediately.", update.Name, update.InstalledVersion, update.AvailableVersion, permissions)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package preferences
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/tentacle"
|
||||
)
|
||||
|
||||
func TestTentacleUpdateConfirmationDescribesPermissionChanges(t *testing.T) {
|
||||
entry := tentacle.Entry{Presentation: true}
|
||||
update := tentacle.AvailableUpdate{Name: "Example", InstalledVersion: "1.0", AvailableVersion: "1.1"}
|
||||
manifest := tentacle.Manifest{Capabilities: []string{"presentation", "interaction", "reader-settings"}}
|
||||
message := tentacleUpdateConfirmation(entry, update, manifest)
|
||||
for _, want := range []string{
|
||||
"Update Example from version 1.0 to version 1.1?",
|
||||
"Current capabilities: presentation.",
|
||||
"Repository declares: presentation, interaction, reader-settings.",
|
||||
"Changes take effect immediately.",
|
||||
} {
|
||||
if !strings.Contains(message, want) {
|
||||
t.Fatalf("confirmation missing %q: %s", want, message)
|
||||
}
|
||||
}
|
||||
message = tentacleUpdateConfirmation(tentacle.Entry{}, update, tentacle.Manifest{})
|
||||
if !strings.Contains(message, "Current capabilities: none. Repository declares: none.") {
|
||||
t.Fatalf("empty capability sets were not described: %s", message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTentacleInstallConfirmationDescribesInteractionAndSettings(t *testing.T) {
|
||||
entry := tentacle.Entry{Name: "Example", Version: "1.1", Repository: "https://example.org/tentacles"}
|
||||
manifest := tentacle.Manifest{Capabilities: []string{"presentation", "interaction", "reader-settings"}}
|
||||
message := tentacleInstallConfirmation(entry, manifest, "Install and enable")
|
||||
for _, want := range []string{
|
||||
"Install and enable Example version 1.1 from https://example.org/tentacles?",
|
||||
"read the focused item and clipboard when invoked",
|
||||
"temporarily change the reader voice configuration",
|
||||
"resource limits do not protect your files or network",
|
||||
} {
|
||||
if !strings.Contains(message, want) {
|
||||
t.Fatalf("confirmation missing %q: %s", want, message)
|
||||
}
|
||||
}
|
||||
message = tentacleInstallConfirmation(entry, tentacle.Manifest{}, "Install")
|
||||
if !strings.Contains(message, "This tentacle can register reader commands.") || strings.Contains(message, "write clipboard text") {
|
||||
t.Fatalf("command-only installation described incorrectly: %s", message)
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,7 @@ package preferences
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
@@ -165,171 +162,6 @@ func (page *tentaclePage) populate(snapshot *tentacle.Snapshot) {
|
||||
page.render()
|
||||
}
|
||||
|
||||
func (page *tentaclePage) action(action int) (*tentacle.ManagementRequest, error) {
|
||||
if action == 16 {
|
||||
if selected := page.selected(); selected != nil {
|
||||
page.selectedKey = selected.key
|
||||
}
|
||||
page.controls()
|
||||
return nil, nil
|
||||
}
|
||||
if action == 17 {
|
||||
page.render()
|
||||
return nil, nil
|
||||
}
|
||||
if action == 15 {
|
||||
return &tentacle.ManagementRequest{Action: "list"}, nil
|
||||
}
|
||||
if page.snapshot == nil || page.snapshot.Suppressed || page.snapshot.Message != "" {
|
||||
message := "Tentacle management is unavailable for this run."
|
||||
if page.snapshot != nil && page.snapshot.Message != "" {
|
||||
message = page.snapshot.Message
|
||||
}
|
||||
return nil, errors.New(message)
|
||||
}
|
||||
if action == 9 {
|
||||
id := C.CString("tentacleRepositoryURL")
|
||||
origin, err := tentacle.RepositoryURL(C.GoString(C.prefs_entry_get(id)))
|
||||
C.free(unsafe.Pointer(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: "repository-add", URL: origin}, nil
|
||||
}
|
||||
if action == 12 || action == 18 {
|
||||
origin := page.origin()
|
||||
if origin == "" {
|
||||
return nil, errors.New("Select a repository tab first.")
|
||||
}
|
||||
operation := "repository-remove"
|
||||
if action == 18 {
|
||||
operation = "repository-refresh"
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: operation, URL: origin}, nil
|
||||
}
|
||||
selected := page.selected()
|
||||
if selected == nil {
|
||||
return nil, errors.New("Select a tentacle first.")
|
||||
}
|
||||
page.selectedKey = selected.key
|
||||
if action == 21 {
|
||||
if !selected.installed {
|
||||
return nil, errors.New("Install this tentacle first.")
|
||||
}
|
||||
entry := selected.status.Entry
|
||||
for _, update := range page.snapshot.Updates {
|
||||
if update.ID != entry.ID {
|
||||
continue
|
||||
}
|
||||
permissions := ""
|
||||
foundManifest := false
|
||||
for _, repository := range page.snapshot.Repositories {
|
||||
if repository.URL != update.RepositoryURL || repository.ID != update.RepositoryID {
|
||||
continue
|
||||
}
|
||||
for _, manifest := range repository.Tentacles {
|
||||
if manifest.ID != update.LocalID {
|
||||
continue
|
||||
}
|
||||
foundManifest = true
|
||||
var previous []string
|
||||
if entry.Presentation {
|
||||
previous = append(previous, "presentation")
|
||||
}
|
||||
if entry.Interaction {
|
||||
previous = append(previous, "interaction")
|
||||
}
|
||||
if entry.ReaderSettings {
|
||||
previous = append(previous, "reader-settings")
|
||||
}
|
||||
if len(previous) == 0 {
|
||||
previous = append(previous, "none")
|
||||
}
|
||||
declared := manifest.Capabilities
|
||||
if len(declared) == 0 {
|
||||
declared = []string{"none"}
|
||||
}
|
||||
permissions = "Current capabilities: " + strings.Join(previous, ", ") +
|
||||
". Repository declares: " + strings.Join(declared, ", ") + "."
|
||||
}
|
||||
}
|
||||
if !foundManifest {
|
||||
return nil, errors.New("Updated package manifest is unavailable; refresh the repository before upgrading.")
|
||||
}
|
||||
message := fmt.Sprintf("Update %s from version %s to version %s?\n\n%s\n\nOnly update packages from publishers you trust. Tentacles run with your account's access.\n\nChanges take effect immediately.", update.Name, update.InstalledVersion, update.AvailableVersion, permissions)
|
||||
text, button := C.CString(message), C.CString("Update")
|
||||
accepted := C.prefs_tentacle_confirm(text, button)
|
||||
C.free(unsafe.Pointer(text))
|
||||
C.free(unsafe.Pointer(button))
|
||||
if accepted == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: "upgrade", ID: update.LocalID, URL: update.RepositoryURL}, nil
|
||||
}
|
||||
return nil, errors.New("No newer version is available for the selected tentacle. Refresh its repository to check again.")
|
||||
}
|
||||
if !selected.installed {
|
||||
if action != 11 && action != 19 {
|
||||
return nil, errors.New("Install this tentacle first.")
|
||||
}
|
||||
entry := selected.status.Entry
|
||||
var manifest *tentacle.Manifest
|
||||
for _, repository := range page.snapshot.Repositories {
|
||||
if repository.URL == entry.Repository && repository.ID == entry.RepositoryID {
|
||||
for index := range repository.Tentacles {
|
||||
if repository.Tentacles[index].ID == entry.LocalID {
|
||||
manifest = &repository.Tentacles[index]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if manifest == nil || len(manifest.Releases) == 0 {
|
||||
return nil, errors.New("No package has been published for this tentacle. Refresh the repository after a release is published.")
|
||||
}
|
||||
permissions := "This tentacle can register reader commands."
|
||||
if slices.Contains(manifest.Capabilities, "presentation") {
|
||||
permissions = "This tentacle can register reader commands and send speech and braille messages."
|
||||
}
|
||||
if slices.Contains(manifest.Capabilities, "interaction") {
|
||||
permissions = "This tentacle can register reader commands, send speech and braille messages, open internal forms, read the focused item and clipboard when invoked, and write clipboard text."
|
||||
}
|
||||
if slices.Contains(manifest.Capabilities, "reader-settings") {
|
||||
permissions += " It can also add preferences pages and quick settings, inspect speech voices, and temporarily change the reader voice configuration."
|
||||
}
|
||||
operation, label := "install", "Install"
|
||||
if action == 11 {
|
||||
operation, label = "install-enable", "Install and enable"
|
||||
}
|
||||
message := fmt.Sprintf("%s %s version %s from %s?\n\n%s\n\nOnly install packages from publishers you trust. Tentacles run with your account's access; resource limits do not protect your files or network.\n\nTentacle management changes take effect immediately.", label, entry.Name, entry.Version, entry.Repository, permissions)
|
||||
text, button := C.CString(message), C.CString(label)
|
||||
accepted := C.prefs_tentacle_confirm(text, button)
|
||||
C.free(unsafe.Pointer(text))
|
||||
C.free(unsafe.Pointer(button))
|
||||
if accepted == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: operation, ID: entry.LocalID, URL: entry.Repository}, nil
|
||||
}
|
||||
operation := ""
|
||||
switch action {
|
||||
case 11:
|
||||
operation = "enable"
|
||||
if selected.status.Entry.Enabled {
|
||||
operation = "disable"
|
||||
}
|
||||
case 13:
|
||||
operation = "retry"
|
||||
case 14:
|
||||
operation = "remove"
|
||||
case 20:
|
||||
operation = "settings"
|
||||
default:
|
||||
return nil, errors.New("Unknown tentacle action.")
|
||||
}
|
||||
return &tentacle.ManagementRequest{Action: operation, ID: selected.status.Entry.ID}, nil
|
||||
}
|
||||
|
||||
func (page *tentaclePage) accepted(request *tentacle.ManagementRequest) {
|
||||
if request.Action == "repository-add" {
|
||||
id, empty := C.CString("tentacleRepositoryURL"), C.CString("")
|
||||
|
||||
@@ -146,7 +146,7 @@ func Run(ctx context.Context, input io.Reader, output io.Writer) error {
|
||||
session.refreshSpeechVoices()
|
||||
session.refreshKeyBindingLayout()
|
||||
action := C.prefs_action()
|
||||
if action >= 9 && action <= 21 && !busy {
|
||||
if action >= C.PREFS_TENTACLE_REPOSITORY_ADD && action <= C.PREFS_TENTACLE_UPDATE && !busy {
|
||||
request, err := tentacles.action(int(action))
|
||||
if err != nil {
|
||||
status(err.Error(), true)
|
||||
|
||||
Reference in new issue
Block a user