1
0
Fork 0
mirror of https://github.com/Luzifer/streamdeck.git synced 2024-12-29 22:21:24 +00:00

Fix: Prevent drawing elements from previous page

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2020-06-06 16:13:49 +02:00
parent 42c0ec2f11
commit c8a6c79369
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
5 changed files with 43 additions and 15 deletions

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"image/color" "image/color"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -12,7 +13,7 @@ func init() {
type displayElementColor struct{} type displayElementColor struct{}
func (d displayElementColor) Display(idx int, attributes map[string]interface{}) error { func (d displayElementColor) Display(ctx context.Context, idx int, attributes map[string]interface{}) error {
if name, ok := attributes["color"].(string); ok { if name, ok := attributes["color"].(string); ok {
return d.displayPredefinedColor(idx, name) return d.displayPredefinedColor(idx, name)
} }
@ -22,6 +23,11 @@ func (d displayElementColor) Display(idx int, attributes map[string]interface{})
return errors.New("RGBA color definition needs 4 hex values") return errors.New("RGBA color definition needs 4 hex values")
} }
if err := ctx.Err(); err != nil {
// Page context was cancelled, do not draw
return err
}
return sd.FillColor(idx, color.RGBA{uint8(rgba[0].(int)), uint8(rgba[1].(int)), uint8(rgba[2].(int)), uint8(rgba[3].(int))}) return sd.FillColor(idx, color.RGBA{uint8(rgba[0].(int)), uint8(rgba[1].(int)), uint8(rgba[2].(int)), uint8(rgba[3].(int))})
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"image" "image"
"image/color" "image/color"
@ -30,7 +31,7 @@ type displayElementExec struct {
running bool running bool
} }
func (d displayElementExec) Display(idx int, attributes map[string]interface{}) error { func (d displayElementExec) Display(ctx context.Context, idx int, attributes map[string]interface{}) error {
var ( var (
err error err error
img draw.Image = image.NewRGBA(image.Rect(0, 0, sd.IconSize(), sd.IconSize())) img draw.Image = image.NewRGBA(image.Rect(0, 0, sd.IconSize(), sd.IconSize()))
@ -141,6 +142,11 @@ func (d displayElementExec) Display(idx int, attributes map[string]interface{})
return nil return nil
} }
if err := ctx.Err(); err != nil {
// Page context was cancelled, do not draw
return err
}
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image") return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
} }
@ -152,7 +158,7 @@ func (d displayElementExec) NeedsLoop(attributes map[string]interface{}) bool {
return false return false
} }
func (d *displayElementExec) StartLoopDisplay(idx int, attributes map[string]interface{}) error { func (d *displayElementExec) StartLoopDisplay(ctx context.Context, idx int, attributes map[string]interface{}) error {
d.running = true d.running = true
var interval = 5 * time.Second var interval = 5 * time.Second
@ -166,7 +172,7 @@ func (d *displayElementExec) StartLoopDisplay(idx int, attributes map[string]int
return return
} }
if err := d.Display(idx, attributes); err != nil { if err := d.Display(ctx, idx, attributes); err != nil {
log.WithError(err).Error("Unable to refresh element") log.WithError(err).Error("Unable to refresh element")
} }
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"image" "image"
_ "image/jpeg" _ "image/jpeg"
_ "image/png" _ "image/png"
@ -15,7 +16,7 @@ func init() {
type displayElementImage struct{} type displayElementImage struct{}
func (d displayElementImage) Display(idx int, attributes map[string]interface{}) error { func (d displayElementImage) Display(ctx context.Context, idx int, attributes map[string]interface{}) error {
filename, ok := attributes["path"].(string) filename, ok := attributes["path"].(string)
if !ok { if !ok {
return errors.New("No path attribute specified") return errors.New("No path attribute specified")
@ -34,5 +35,10 @@ func (d displayElementImage) Display(idx int, attributes map[string]interface{})
img = autoSizeImage(img, sd.IconSize()) img = autoSizeImage(img, sd.IconSize())
if err := ctx.Err(); err != nil {
// Page context was cancelled, do not draw
return err
}
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image") return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
@ -28,10 +29,12 @@ var (
currentBrightness int currentBrightness int
userConfig config userConfig config
activePage page activePage page
activePageName string activePageCtx context.Context
activeLoops []refreshingDisplayElement activePageCtxCancel context.CancelFunc
activePageName string
activeLoops []refreshingDisplayElement
sd *streamdeck.Client sd *streamdeck.Client
@ -208,6 +211,11 @@ func main() {
} }
func togglePage(page string) error { func togglePage(page string) error {
if activePageCtxCancel != nil {
// Ensure old display events are no longer executed
activePageCtxCancel()
}
// Reset potentially running looped elements // Reset potentially running looped elements
for _, l := range activeLoops { for _, l := range activeLoops {
if err := l.StopLoopDisplay(); err != nil { if err := l.StopLoopDisplay(); err != nil {
@ -218,11 +226,12 @@ func togglePage(page string) error {
activePage = userConfig.Pages[page] activePage = userConfig.Pages[page]
activePageName = page activePageName = page
activePageCtx, activePageCtxCancel = context.WithCancel(context.Background())
sd.ClearAllKeys() sd.ClearAllKeys()
for idx, kd := range activePage.Keys { for idx, kd := range activePage.Keys {
if kd.Display.Type != "" { if kd.Display.Type != "" {
if err := callDisplayElement(idx, kd); err != nil { if err := callDisplayElement(activePageCtx, idx, kd); err != nil {
return errors.Wrapf(err, "Unable to execute display element on key %d", idx) return errors.Wrapf(err, "Unable to execute display element on key %d", idx)
} }
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"reflect" "reflect"
"sync" "sync"
@ -13,12 +14,12 @@ type action interface {
} }
type displayElement interface { type displayElement interface {
Display(idx int, attributes map[string]interface{}) error Display(ctx context.Context, idx int, attributes map[string]interface{}) error
} }
type refreshingDisplayElement interface { type refreshingDisplayElement interface {
NeedsLoop(attributes map[string]interface{}) bool NeedsLoop(attributes map[string]interface{}) bool
StartLoopDisplay(idx int, attributes map[string]interface{}) error StartLoopDisplay(ctx context.Context, idx int, attributes map[string]interface{}) error
StopLoopDisplay() error StopLoopDisplay() error
} }
@ -54,7 +55,7 @@ func callAction(a dynamicElement) error {
return inst.Execute(a.Attributes) return inst.Execute(a.Attributes)
} }
func callDisplayElement(idx int, kd keyDefinition) error { func callDisplayElement(ctx context.Context, idx int, kd keyDefinition) error {
t, ok := registeredDisplayElements[kd.Display.Type] t, ok := registeredDisplayElements[kd.Display.Type]
if !ok { if !ok {
return errors.Errorf("Unknown display type %q", kd.Display.Type) return errors.Errorf("Unknown display type %q", kd.Display.Type)
@ -74,8 +75,8 @@ func callDisplayElement(idx int, kd keyDefinition) error {
"display_type": kd.Display.Type, "display_type": kd.Display.Type,
}).Debug("Starting loop") }).Debug("Starting loop")
activeLoops = append(activeLoops, inst.(refreshingDisplayElement)) activeLoops = append(activeLoops, inst.(refreshingDisplayElement))
return inst.(refreshingDisplayElement).StartLoopDisplay(idx, kd.Display.Attributes) return inst.(refreshingDisplayElement).StartLoopDisplay(ctx, idx, kd.Display.Attributes)
} }
return inst.(displayElement).Display(idx, kd.Display.Attributes) return inst.(displayElement).Display(ctx, idx, kd.Display.Attributes)
} }