2023-01-08 23:03:19 -07:00
|
|
|
package x
|
|
|
|
|
|
|
|
import "git.tebibyte.media/sashakoshka/tomo"
|
|
|
|
|
|
|
|
import "github.com/jezek/xgbutil"
|
|
|
|
import "github.com/jezek/xgb/xproto"
|
|
|
|
import "github.com/jezek/xgbutil/xevent"
|
2023-04-10 16:07:49 -06:00
|
|
|
import "github.com/jezek/xgbutil/keybind"
|
|
|
|
import "github.com/jezek/xgbutil/mousebind"
|
2023-01-08 23:03:19 -07:00
|
|
|
|
|
|
|
// Backend is an instance of an X backend.
|
|
|
|
type Backend struct {
|
|
|
|
connection *xgbutil.XUtil
|
|
|
|
|
|
|
|
doChannel chan(func ())
|
|
|
|
|
|
|
|
modifierMasks struct {
|
|
|
|
capsLock uint16
|
|
|
|
shiftLock uint16
|
|
|
|
numLock uint16
|
|
|
|
modeSwitch uint16
|
|
|
|
|
|
|
|
alt uint16
|
|
|
|
meta uint16
|
|
|
|
super uint16
|
|
|
|
hyper uint16
|
|
|
|
}
|
|
|
|
|
2023-03-30 23:06:29 -06:00
|
|
|
theme tomo.Theme
|
|
|
|
config tomo.Config
|
2023-02-02 23:35:59 -07:00
|
|
|
|
2023-03-14 16:54:24 -06:00
|
|
|
windows map[xproto.Window] *window
|
2023-02-16 15:22:33 -07:00
|
|
|
|
|
|
|
open bool
|
2023-01-08 23:03:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewBackend instantiates an X backend.
|
|
|
|
func NewBackend () (output tomo.Backend, err error) {
|
|
|
|
backend := &Backend {
|
2023-03-30 23:06:29 -06:00
|
|
|
windows: map[xproto.Window] *window { },
|
2023-03-27 18:44:39 -06:00
|
|
|
doChannel: make(chan func (), 32),
|
2023-03-30 23:06:29 -06:00
|
|
|
open: true,
|
2023-01-08 23:03:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// connect to X
|
|
|
|
backend.connection, err = xgbutil.NewConn()
|
|
|
|
if err != nil { return }
|
|
|
|
backend.initializeKeymapInformation()
|
|
|
|
|
2023-04-10 16:07:49 -06:00
|
|
|
keybind.Initialize(backend.connection)
|
|
|
|
mousebind.Initialize(backend.connection)
|
|
|
|
|
2023-01-08 23:03:19 -07:00
|
|
|
output = backend
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run runs the backend's event loop. This method will not exit until Stop() is
|
|
|
|
// called, or the backend experiences a fatal error.
|
|
|
|
func (backend *Backend) Run () (err error) {
|
|
|
|
backend.assert()
|
|
|
|
pingBefore,
|
|
|
|
pingAfter,
|
|
|
|
pingQuit := xevent.MainPing(backend.connection)
|
|
|
|
for {
|
|
|
|
select {
|
2023-01-17 18:16:03 -07:00
|
|
|
case <- pingBefore:
|
|
|
|
<- pingAfter
|
2023-01-08 23:03:19 -07:00
|
|
|
case callback := <- backend.doChannel:
|
|
|
|
callback()
|
2023-04-13 22:25:05 -06:00
|
|
|
for _, window := range backend.windows {
|
|
|
|
window.system.afterEvent()
|
|
|
|
}
|
2023-01-17 18:16:03 -07:00
|
|
|
case <- pingQuit:
|
|
|
|
return
|
2023-01-08 23:03:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop gracefully closes the connection and stops the event loop.
|
|
|
|
func (backend *Backend) Stop () {
|
|
|
|
backend.assert()
|
2023-02-16 15:22:33 -07:00
|
|
|
if !backend.open { return }
|
|
|
|
backend.open = false
|
|
|
|
|
2023-03-14 16:54:24 -06:00
|
|
|
toClose := []*window { }
|
2023-01-08 23:03:19 -07:00
|
|
|
for _, window := range backend.windows {
|
2023-02-03 15:50:45 -07:00
|
|
|
toClose = append(toClose, window)
|
|
|
|
}
|
|
|
|
for _, window := range toClose {
|
2023-01-08 23:03:19 -07:00
|
|
|
window.Close()
|
|
|
|
}
|
|
|
|
xevent.Quit(backend.connection)
|
|
|
|
backend.connection.Conn().Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do executes the specified callback within the main thread as soon as
|
|
|
|
// possible. This function can be safely called from other threads.
|
|
|
|
func (backend *Backend) Do (callback func ()) {
|
|
|
|
backend.assert()
|
|
|
|
backend.doChannel <- callback
|
|
|
|
}
|
|
|
|
|
2023-02-02 23:35:59 -07:00
|
|
|
// SetTheme sets the theme of all open windows.
|
2023-03-30 23:06:29 -06:00
|
|
|
func (backend *Backend) SetTheme (theme tomo.Theme) {
|
2023-02-02 23:35:59 -07:00
|
|
|
backend.assert()
|
|
|
|
backend.theme = theme
|
|
|
|
for _, window := range backend.windows {
|
|
|
|
window.SetTheme(theme)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetConfig sets the configuration of all open windows.
|
2023-03-30 23:06:29 -06:00
|
|
|
func (backend *Backend) SetConfig (config tomo.Config) {
|
2023-02-02 23:35:59 -07:00
|
|
|
backend.assert()
|
|
|
|
backend.config = config
|
|
|
|
for _, window := range backend.windows {
|
|
|
|
window.SetConfig(config)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-08 23:03:19 -07:00
|
|
|
func (backend *Backend) assert () {
|
|
|
|
if backend == nil { panic("nil backend") }
|
|
|
|
}
|
|
|
|
|
|
|
|
func init () {
|
|
|
|
tomo.RegisterBackend(NewBackend)
|
|
|
|
}
|