nasin/application.go
Sasha Koshka 1bc08bcfe4 Add ApplicationURLOpener interface
Eventually we can have nasin parse cli args and figure out what
files to open, instructing the application to open those files.
We will also be able to have nasin connect to dbus using the
application ID and open files in an already running instance of the
application.
2024-06-06 22:38:51 -04:00

152 lines
5.2 KiB
Go

package nasin
import "log"
import "image"
import "strings"
import "net/url"
import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/nasin/internal/registrar"
// Application represents an application object.
type Application interface {
// Describe returns a description of the application.
Describe () ApplicationDescription
// Init performs the initial setup of the application.
Init () error
}
// ApplicationURLOpener is an application that can open a URL.
type ApplicationURLOpener interface {
Application
// OpenURL opens a new window with the contents of the given URL. If the
// given URL is unsupported, it returns an error (for example, an image
// viewer is not expected to open a text file). If the URL scheme is
// empty, file:// is assumed.
//
// Applications should support the file:// scheme at the very least, and
// should also support others like http:// and https:// if possible.
OpenURL (*url.URL) error
}
// ApplicationDescription describes the name and type of an application.
type ApplicationDescription struct {
// The name of the application.
Name string
// The ID of the application. This should be a well-known name, that is,
// a reversed domain name owned by the author with the application name
// as the subdomain.
//
// For example:
// com.example.Application
ID string
// Role describes what the application does.
Role ApplicationRole
}
// String satisfies the fmt.Stringer interface.
func (application ApplicationDescription) String () string {
if application.Name == "" {
return string(application.Role)
} else {
return application.Name
}
}
// ApplicationRole describes what an application does.
type ApplicationRole string; const (
RoleUnknown ApplicationRole = ""
RoleWebBrowser ApplicationRole = "Web Browser"
RoleMesssanger ApplicationRole = "Messsanger"
RolePhone ApplicationRole = "Phone"
RoleMail ApplicationRole = "Mail"
RoleTerminalEmulator ApplicationRole = "Terminal Emulator"
RoleFileBrowser ApplicationRole = "File Browser"
RoleTextEditor ApplicationRole = "Text Editor"
RoleDocumentViewer ApplicationRole = "Document Viewer"
RoleWordProcessor ApplicationRole = "Word Processor"
RoleSpreadsheet ApplicationRole = "Spreadsheet"
RoleSlideshow ApplicationRole = "Slideshow"
RoleCalculator ApplicationRole = "Calculator"
RolePreferences ApplicationRole = "Preferences"
RoleProcessManager ApplicationRole = "Process Manager"
RoleSystemInformation ApplicationRole = "System Information"
RoleManual ApplicationRole = "Manual"
RoleCamera ApplicationRole = "Camera"
RoleImageViewer ApplicationRole = "Image Viewer"
RoleMediaPlayer ApplicationRole = "Media Player"
RoleImageEditor ApplicationRole = "Image Editor"
RoleAudioEditor ApplicationRole = "Audio Editor"
RoleVideoEditor ApplicationRole = "Video Editor"
RoleClock ApplicationRole = "Clock"
RoleCalendar ApplicationRole = "Calendar"
RoleChecklist ApplicationRole = "Checklist"
)
// Icon returns the icon ID for this role.
func (role ApplicationRole) Icon () tomo.Icon {
if role == "" {
return tomo.IconApplication
} else {
return tomo.Icon("Application" + strings.ReplaceAll(string(role), " ", ""))
}
}
// RunApplication is like tomo.Run, but runs an application. If something fails
// to initialize, an error is written to the standard logger.
func RunApplication (application Application) {
err := registrar.Init()
if err != nil { log.Fatal("nasin: could not init registry:", err) }
err = tomo.Run(func () {
err := application.Init()
if err != nil { log.Fatal("nasin: could not run application:", err) }
})
if err != nil { log.Fatal("nasin: could not run application:", err) }
}
// NewApplicationWindow creates a window for an application. It will
// automatically set window information to signal to the OS that the window is
// owned by the application. The window's icon will be automatically set by
// looking for an icon with the name of the application's ID. If that is not
// found, the default icon for the application's ApplicationRole will used.
func NewApplicationWindow (application Application, bounds image.Rectangle) (tomo.MainWindow, error) {
window, err := tomo.NewWindow(bounds)
if err != nil { return nil, err }
description := application.Describe()
window.SetTitle(description.Name)
setApplicationWindowIcon(window, description)
return window, nil
}
func setApplicationWindowIcon (window tomo.Window, description ApplicationDescription) {
allSizes := func (icon tomo.Icon) (sizes []image.Image) {
small := icon.Texture(tomo.IconSizeSmall)
medium := icon.Texture(tomo.IconSizeMedium)
large := icon.Texture(tomo.IconSizeLarge)
if small != nil { sizes = append(sizes, small) }
if medium != nil { sizes = append(sizes, medium) }
if large != nil { sizes = append(sizes, large) }
return sizes
}
if sizes := allSizes(tomo.Icon(description.ID)); len(sizes) > 0 {
println("direct icon worked", tomo.Icon(description.ID))
window.SetIcon(sizes...)
return
}
if sizes := allSizes(description.Role.Icon()); len(sizes) > 0 {
println("role icon worked", description.Role.Icon())
window.SetIcon(sizes...)
return
}
}