mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-14 09:42:10 -04:00
core/cli: add dpms off/on via wlr-output-power-management
This commit is contained in:
@@ -368,6 +368,7 @@ func getCommonCommands() []*cobra.Command {
|
|||||||
pluginsCmd,
|
pluginsCmd,
|
||||||
dank16Cmd,
|
dank16Cmd,
|
||||||
brightnessCmd,
|
brightnessCmd,
|
||||||
|
dpmsCmd,
|
||||||
keybindsCmd,
|
keybindsCmd,
|
||||||
greeterCmd,
|
greeterCmd,
|
||||||
setupCmd,
|
setupCmd,
|
||||||
|
|||||||
84
core/cmd/dms/commands_dpms.go
Normal file
84
core/cmd/dms/commands_dpms.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dpmsCmd = &cobra.Command{
|
||||||
|
Use: "dpms",
|
||||||
|
Short: "Control display power management",
|
||||||
|
}
|
||||||
|
|
||||||
|
var dpmsOnCmd = &cobra.Command{
|
||||||
|
Use: "on [output]",
|
||||||
|
Short: "Turn display(s) on",
|
||||||
|
Args: cobra.MaximumNArgs(1),
|
||||||
|
Run: runDPMSOn,
|
||||||
|
}
|
||||||
|
|
||||||
|
var dpmsOffCmd = &cobra.Command{
|
||||||
|
Use: "off [output]",
|
||||||
|
Short: "Turn display(s) off",
|
||||||
|
Args: cobra.MaximumNArgs(1),
|
||||||
|
Run: runDPMSOff,
|
||||||
|
}
|
||||||
|
|
||||||
|
var dpmsListCmd = &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "List outputs",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
Run: runDPMSList,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dpmsCmd.AddCommand(dpmsOnCmd, dpmsOffCmd, dpmsListCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDPMSOn(cmd *cobra.Command, args []string) {
|
||||||
|
outputName := ""
|
||||||
|
if len(args) > 0 {
|
||||||
|
outputName = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := newDPMSClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
if err := client.SetDPMS(outputName, true); err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDPMSOff(cmd *cobra.Command, args []string) {
|
||||||
|
outputName := ""
|
||||||
|
if len(args) > 0 {
|
||||||
|
outputName = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := newDPMSClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
if err := client.SetDPMS(outputName, false); err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDPMSList(cmd *cobra.Command, args []string) {
|
||||||
|
client, err := newDPMSClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
for _, output := range client.ListOutputs() {
|
||||||
|
fmt.Println(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
345
core/cmd/dms/dpms_client.go
Normal file
345
core/cmd/dms/dpms_client.go
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_power"
|
||||||
|
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cmd struct {
|
||||||
|
fn func()
|
||||||
|
done chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
type dpmsClient struct {
|
||||||
|
display *wlclient.Display
|
||||||
|
ctx *wlclient.Context
|
||||||
|
powerMgr *wlr_output_power.ZwlrOutputPowerManagerV1
|
||||||
|
outputs map[string]*outputState
|
||||||
|
mu sync.Mutex
|
||||||
|
syncRound int
|
||||||
|
done bool
|
||||||
|
err error
|
||||||
|
cmdq chan cmd
|
||||||
|
stopChan chan struct{}
|
||||||
|
wg sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
type outputState struct {
|
||||||
|
wlOutput *wlclient.Output
|
||||||
|
powerCtrl *wlr_output_power.ZwlrOutputPowerV1
|
||||||
|
name string
|
||||||
|
mode uint32
|
||||||
|
failed bool
|
||||||
|
waitCh chan struct{}
|
||||||
|
wantMode *uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dpmsClient) post(fn func()) {
|
||||||
|
done := make(chan error, 1)
|
||||||
|
select {
|
||||||
|
case c.cmdq <- cmd{fn: fn, done: done}:
|
||||||
|
<-done
|
||||||
|
case <-c.stopChan:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dpmsClient) waylandActor() {
|
||||||
|
defer c.wg.Done()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.stopChan:
|
||||||
|
return
|
||||||
|
case cmd := <-c.cmdq:
|
||||||
|
cmd.fn()
|
||||||
|
close(cmd.done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDPMSClient() (*dpmsClient, error) {
|
||||||
|
display, err := wlclient.Connect("")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to connect to Wayland: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &dpmsClient{
|
||||||
|
display: display,
|
||||||
|
ctx: display.Context(),
|
||||||
|
outputs: make(map[string]*outputState),
|
||||||
|
cmdq: make(chan cmd, 128),
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
c.wg.Add(1)
|
||||||
|
go c.waylandActor()
|
||||||
|
|
||||||
|
registry, err := display.GetRegistry()
|
||||||
|
if err != nil {
|
||||||
|
display.Context().Close()
|
||||||
|
return nil, fmt.Errorf("failed to get registry: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) {
|
||||||
|
switch e.Interface {
|
||||||
|
case wlr_output_power.ZwlrOutputPowerManagerV1InterfaceName:
|
||||||
|
powerMgr := wlr_output_power.NewZwlrOutputPowerManagerV1(c.ctx)
|
||||||
|
version := e.Version
|
||||||
|
if version > 1 {
|
||||||
|
version = 1
|
||||||
|
}
|
||||||
|
if err := registry.Bind(e.Name, e.Interface, version, powerMgr); err == nil {
|
||||||
|
c.powerMgr = powerMgr
|
||||||
|
}
|
||||||
|
|
||||||
|
case "wl_output":
|
||||||
|
output := wlclient.NewOutput(c.ctx)
|
||||||
|
version := e.Version
|
||||||
|
if version > 4 {
|
||||||
|
version = 4
|
||||||
|
}
|
||||||
|
if err := registry.Bind(e.Name, e.Interface, version, output); err == nil {
|
||||||
|
outputID := fmt.Sprintf("output-%d", output.ID())
|
||||||
|
state := &outputState{
|
||||||
|
wlOutput: output,
|
||||||
|
name: outputID,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.outputs[outputID] = state
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
output.SetNameHandler(func(ev wlclient.OutputNameEvent) {
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.outputs, state.name)
|
||||||
|
state.name = ev.Name
|
||||||
|
c.outputs[ev.Name] = state
|
||||||
|
c.mu.Unlock()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
syncCallback, err := display.Sync()
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, fmt.Errorf("failed to sync display: %w", err)
|
||||||
|
}
|
||||||
|
syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) {
|
||||||
|
c.handleSync()
|
||||||
|
})
|
||||||
|
|
||||||
|
for !c.done {
|
||||||
|
if err := c.ctx.Dispatch(); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, fmt.Errorf("dispatch error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dpmsClient) handleSync() {
|
||||||
|
c.syncRound++
|
||||||
|
|
||||||
|
switch c.syncRound {
|
||||||
|
case 1:
|
||||||
|
if c.powerMgr == nil {
|
||||||
|
c.err = fmt.Errorf("wlr-output-power-management protocol not supported by compositor")
|
||||||
|
c.done = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
for _, state := range c.outputs {
|
||||||
|
powerCtrl, err := c.powerMgr.GetOutputPower(state.wlOutput)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
state.powerCtrl = powerCtrl
|
||||||
|
|
||||||
|
powerCtrl.SetModeHandler(func(e wlr_output_power.ZwlrOutputPowerV1ModeEvent) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if state.powerCtrl == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.mode = e.Mode
|
||||||
|
if state.wantMode != nil && e.Mode == *state.wantMode && state.waitCh != nil {
|
||||||
|
close(state.waitCh)
|
||||||
|
state.wantMode = nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
powerCtrl.SetFailedHandler(func(e wlr_output_power.ZwlrOutputPowerV1FailedEvent) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if state.powerCtrl == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.failed = true
|
||||||
|
if state.waitCh != nil {
|
||||||
|
close(state.waitCh)
|
||||||
|
state.wantMode = nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
syncCallback, err := c.display.Sync()
|
||||||
|
if err != nil {
|
||||||
|
c.err = fmt.Errorf("failed to sync display: %w", err)
|
||||||
|
c.done = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) {
|
||||||
|
c.handleSync()
|
||||||
|
})
|
||||||
|
|
||||||
|
default:
|
||||||
|
c.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dpmsClient) ListOutputs() []string {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
names := make([]string, 0, len(c.outputs))
|
||||||
|
for name := range c.outputs {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dpmsClient) SetDPMS(outputName string, on bool) error {
|
||||||
|
var mode uint32
|
||||||
|
if on {
|
||||||
|
mode = uint32(wlr_output_power.ZwlrOutputPowerV1ModeOn)
|
||||||
|
} else {
|
||||||
|
mode = uint32(wlr_output_power.ZwlrOutputPowerV1ModeOff)
|
||||||
|
}
|
||||||
|
|
||||||
|
var setErr error
|
||||||
|
c.post(func() {
|
||||||
|
c.mu.Lock()
|
||||||
|
var waitStates []*outputState
|
||||||
|
|
||||||
|
if outputName == "" || outputName == "all" {
|
||||||
|
if len(c.outputs) == 0 {
|
||||||
|
c.mu.Unlock()
|
||||||
|
setErr = fmt.Errorf("no outputs found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, state := range c.outputs {
|
||||||
|
if state.powerCtrl == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
state.wantMode = &mode
|
||||||
|
state.waitCh = make(chan struct{})
|
||||||
|
state.failed = false
|
||||||
|
waitStates = append(waitStates, state)
|
||||||
|
state.powerCtrl.SetMode(mode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state, ok := c.outputs[outputName]
|
||||||
|
if !ok {
|
||||||
|
c.mu.Unlock()
|
||||||
|
setErr = fmt.Errorf("output not found: %s", outputName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if state.powerCtrl == nil {
|
||||||
|
c.mu.Unlock()
|
||||||
|
setErr = fmt.Errorf("output %s has nil powerCtrl", outputName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.wantMode = &mode
|
||||||
|
state.waitCh = make(chan struct{})
|
||||||
|
state.failed = false
|
||||||
|
waitStates = append(waitStates, state)
|
||||||
|
state.powerCtrl.SetMode(mode)
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
deadline := time.Now().Add(10 * time.Second)
|
||||||
|
|
||||||
|
for _, state := range waitStates {
|
||||||
|
c.mu.Lock()
|
||||||
|
ch := state.waitCh
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
done := false
|
||||||
|
for !done {
|
||||||
|
if err := c.ctx.Dispatch(); err != nil {
|
||||||
|
setErr = fmt.Errorf("dispatch error: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ch:
|
||||||
|
c.mu.Lock()
|
||||||
|
if state.failed {
|
||||||
|
setErr = fmt.Errorf("compositor reported failed for %s", state.name)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
done = true
|
||||||
|
default:
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
setErr = fmt.Errorf("timeout waiting for mode change on %s", state.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
for _, state := range waitStates {
|
||||||
|
if state.powerCtrl != nil {
|
||||||
|
state.powerCtrl.Destroy()
|
||||||
|
state.powerCtrl = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
c.display.Roundtrip()
|
||||||
|
})
|
||||||
|
|
||||||
|
return setErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dpmsClient) Close() {
|
||||||
|
close(c.stopChan)
|
||||||
|
c.wg.Wait()
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
for _, state := range c.outputs {
|
||||||
|
if state.powerCtrl != nil {
|
||||||
|
state.powerCtrl.Destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.outputs = nil
|
||||||
|
|
||||||
|
if c.powerMgr != nil {
|
||||||
|
c.powerMgr.Destroy()
|
||||||
|
c.powerMgr = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.display != nil {
|
||||||
|
c.ctx.Close()
|
||||||
|
c.display = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
283
core/internal/proto/wlr_output_power/output_power.go
Normal file
283
core/internal/proto/wlr_output_power/output_power.go
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
// Generated by go-wayland-scanner
|
||||||
|
// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner
|
||||||
|
// XML file : internal/proto/xml/wlr-output-power-management-unstable-v1.xml
|
||||||
|
//
|
||||||
|
// wlr_output_power_management_unstable_v1 Protocol Copyright:
|
||||||
|
//
|
||||||
|
// Copyright © 2019 Purism SPC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice (including the next
|
||||||
|
// paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
// Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
package wlr_output_power
|
||||||
|
|
||||||
|
import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
|
|
||||||
|
// ZwlrOutputPowerManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry].
|
||||||
|
// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
|
||||||
|
// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
|
||||||
|
const ZwlrOutputPowerManagerV1InterfaceName = "zwlr_output_power_manager_v1"
|
||||||
|
|
||||||
|
// ZwlrOutputPowerManagerV1 : manager to create per-output power management
|
||||||
|
//
|
||||||
|
// This interface is a manager that allows creating per-output power
|
||||||
|
// management mode controls.
|
||||||
|
type ZwlrOutputPowerManagerV1 struct {
|
||||||
|
client.BaseProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewZwlrOutputPowerManagerV1 : manager to create per-output power management
|
||||||
|
//
|
||||||
|
// This interface is a manager that allows creating per-output power
|
||||||
|
// management mode controls.
|
||||||
|
func NewZwlrOutputPowerManagerV1(ctx *client.Context) *ZwlrOutputPowerManagerV1 {
|
||||||
|
zwlrOutputPowerManagerV1 := &ZwlrOutputPowerManagerV1{}
|
||||||
|
ctx.Register(zwlrOutputPowerManagerV1)
|
||||||
|
return zwlrOutputPowerManagerV1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOutputPower : get a power management for an output
|
||||||
|
//
|
||||||
|
// Create an output power management mode control that can be used to
|
||||||
|
// adjust the power management mode for a given output.
|
||||||
|
func (i *ZwlrOutputPowerManagerV1) GetOutputPower(output *client.Output) (*ZwlrOutputPowerV1, error) {
|
||||||
|
id := NewZwlrOutputPowerV1(i.Context())
|
||||||
|
const opcode = 0
|
||||||
|
const _reqBufLen = 8 + 4 + 4
|
||||||
|
var _reqBuf [_reqBufLen]byte
|
||||||
|
l := 0
|
||||||
|
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], id.ID())
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], output.ID())
|
||||||
|
l += 4
|
||||||
|
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy : destroy the manager
|
||||||
|
//
|
||||||
|
// All objects created by the manager will still remain valid, until their
|
||||||
|
// appropriate destroy request has been called.
|
||||||
|
func (i *ZwlrOutputPowerManagerV1) Destroy() error {
|
||||||
|
defer i.Context().Unregister(i)
|
||||||
|
const opcode = 1
|
||||||
|
const _reqBufLen = 8
|
||||||
|
var _reqBuf [_reqBufLen]byte
|
||||||
|
l := 0
|
||||||
|
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||||
|
l += 4
|
||||||
|
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZwlrOutputPowerV1InterfaceName is the name of the interface as it appears in the [client.Registry].
|
||||||
|
// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
|
||||||
|
// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
|
||||||
|
const ZwlrOutputPowerV1InterfaceName = "zwlr_output_power_v1"
|
||||||
|
|
||||||
|
// ZwlrOutputPowerV1 : adjust power management mode for an output
|
||||||
|
//
|
||||||
|
// This object offers requests to set the power management mode of
|
||||||
|
// an output.
|
||||||
|
type ZwlrOutputPowerV1 struct {
|
||||||
|
client.BaseProxy
|
||||||
|
modeHandler ZwlrOutputPowerV1ModeHandlerFunc
|
||||||
|
failedHandler ZwlrOutputPowerV1FailedHandlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewZwlrOutputPowerV1 : adjust power management mode for an output
|
||||||
|
//
|
||||||
|
// This object offers requests to set the power management mode of
|
||||||
|
// an output.
|
||||||
|
func NewZwlrOutputPowerV1(ctx *client.Context) *ZwlrOutputPowerV1 {
|
||||||
|
zwlrOutputPowerV1 := &ZwlrOutputPowerV1{}
|
||||||
|
ctx.Register(zwlrOutputPowerV1)
|
||||||
|
return zwlrOutputPowerV1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMode : Set an outputs power save mode
|
||||||
|
//
|
||||||
|
// Set an output's power save mode to the given mode. The mode change
|
||||||
|
// is effective immediately. If the output does not support the given
|
||||||
|
// mode a failed event is sent.
|
||||||
|
//
|
||||||
|
// mode: the power save mode to set
|
||||||
|
func (i *ZwlrOutputPowerV1) SetMode(mode uint32) error {
|
||||||
|
const opcode = 0
|
||||||
|
const _reqBufLen = 8 + 4
|
||||||
|
var _reqBuf [_reqBufLen]byte
|
||||||
|
l := 0
|
||||||
|
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], uint32(mode))
|
||||||
|
l += 4
|
||||||
|
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy : destroy this power management
|
||||||
|
//
|
||||||
|
// Destroys the output power management mode control object.
|
||||||
|
func (i *ZwlrOutputPowerV1) Destroy() error {
|
||||||
|
defer i.Context().Unregister(i)
|
||||||
|
const opcode = 1
|
||||||
|
const _reqBufLen = 8
|
||||||
|
var _reqBuf [_reqBufLen]byte
|
||||||
|
l := 0
|
||||||
|
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||||
|
l += 4
|
||||||
|
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||||
|
l += 4
|
||||||
|
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ZwlrOutputPowerV1Mode uint32
|
||||||
|
|
||||||
|
// ZwlrOutputPowerV1Mode :
|
||||||
|
const (
|
||||||
|
// ZwlrOutputPowerV1ModeOff : Output is turned off.
|
||||||
|
ZwlrOutputPowerV1ModeOff ZwlrOutputPowerV1Mode = 0
|
||||||
|
// ZwlrOutputPowerV1ModeOn : Output is turned on, no power saving
|
||||||
|
ZwlrOutputPowerV1ModeOn ZwlrOutputPowerV1Mode = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e ZwlrOutputPowerV1Mode) Name() string {
|
||||||
|
switch e {
|
||||||
|
case ZwlrOutputPowerV1ModeOff:
|
||||||
|
return "off"
|
||||||
|
case ZwlrOutputPowerV1ModeOn:
|
||||||
|
return "on"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ZwlrOutputPowerV1Mode) Value() string {
|
||||||
|
switch e {
|
||||||
|
case ZwlrOutputPowerV1ModeOff:
|
||||||
|
return "0"
|
||||||
|
case ZwlrOutputPowerV1ModeOn:
|
||||||
|
return "1"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ZwlrOutputPowerV1Mode) String() string {
|
||||||
|
return e.Name() + "=" + e.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ZwlrOutputPowerV1Error uint32
|
||||||
|
|
||||||
|
// ZwlrOutputPowerV1Error :
|
||||||
|
const (
|
||||||
|
// ZwlrOutputPowerV1ErrorInvalidMode : nonexistent power save mode
|
||||||
|
ZwlrOutputPowerV1ErrorInvalidMode ZwlrOutputPowerV1Error = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e ZwlrOutputPowerV1Error) Name() string {
|
||||||
|
switch e {
|
||||||
|
case ZwlrOutputPowerV1ErrorInvalidMode:
|
||||||
|
return "invalid_mode"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ZwlrOutputPowerV1Error) Value() string {
|
||||||
|
switch e {
|
||||||
|
case ZwlrOutputPowerV1ErrorInvalidMode:
|
||||||
|
return "1"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ZwlrOutputPowerV1Error) String() string {
|
||||||
|
return e.Name() + "=" + e.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZwlrOutputPowerV1ModeEvent : Report a power management mode change
|
||||||
|
//
|
||||||
|
// Report the power management mode change of an output.
|
||||||
|
//
|
||||||
|
// The mode event is sent after an output changed its power
|
||||||
|
// management mode. The reason can be a client using set_mode or the
|
||||||
|
// compositor deciding to change an output's mode.
|
||||||
|
// This event is also sent immediately when the object is created
|
||||||
|
// so the client is informed about the current power management mode.
|
||||||
|
type ZwlrOutputPowerV1ModeEvent struct {
|
||||||
|
Mode uint32
|
||||||
|
}
|
||||||
|
type ZwlrOutputPowerV1ModeHandlerFunc func(ZwlrOutputPowerV1ModeEvent)
|
||||||
|
|
||||||
|
// SetModeHandler : sets handler for ZwlrOutputPowerV1ModeEvent
|
||||||
|
func (i *ZwlrOutputPowerV1) SetModeHandler(f ZwlrOutputPowerV1ModeHandlerFunc) {
|
||||||
|
i.modeHandler = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZwlrOutputPowerV1FailedEvent : object no longer valid
|
||||||
|
//
|
||||||
|
// This event indicates that the output power management mode control
|
||||||
|
// is no longer valid. This can happen for a number of reasons,
|
||||||
|
// including:
|
||||||
|
// - The output doesn't support power management
|
||||||
|
// - Another client already has exclusive power management mode control
|
||||||
|
// for this output
|
||||||
|
// - The output disappeared
|
||||||
|
//
|
||||||
|
// Upon receiving this event, the client should destroy this object.
|
||||||
|
type ZwlrOutputPowerV1FailedEvent struct{}
|
||||||
|
type ZwlrOutputPowerV1FailedHandlerFunc func(ZwlrOutputPowerV1FailedEvent)
|
||||||
|
|
||||||
|
// SetFailedHandler : sets handler for ZwlrOutputPowerV1FailedEvent
|
||||||
|
func (i *ZwlrOutputPowerV1) SetFailedHandler(f ZwlrOutputPowerV1FailedHandlerFunc) {
|
||||||
|
i.failedHandler = f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ZwlrOutputPowerV1) Dispatch(opcode uint32, fd int, data []byte) {
|
||||||
|
switch opcode {
|
||||||
|
case 0:
|
||||||
|
if i.modeHandler == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var e ZwlrOutputPowerV1ModeEvent
|
||||||
|
l := 0
|
||||||
|
e.Mode = client.Uint32(data[l : l+4])
|
||||||
|
l += 4
|
||||||
|
|
||||||
|
i.modeHandler(e)
|
||||||
|
case 1:
|
||||||
|
if i.failedHandler == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var e ZwlrOutputPowerV1FailedEvent
|
||||||
|
|
||||||
|
i.failedHandler(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_output_power_management_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2019 Purism SPC
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="Control power management modes of outputs">
|
||||||
|
This protocol allows clients to control power management modes
|
||||||
|
of outputs that are currently part of the compositor space. The
|
||||||
|
intent is to allow special clients like desktop shells to power
|
||||||
|
down outputs when the system is idle.
|
||||||
|
|
||||||
|
To modify outputs not currently part of the compositor space see
|
||||||
|
wlr-output-management.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
|
may be added together with the corresponding interface version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version number in
|
||||||
|
the protocol and interface names and resetting the interface version.
|
||||||
|
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||||
|
version number in the protocol and interface names are removed and the
|
||||||
|
interface version number is reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_power_manager_v1" version="1">
|
||||||
|
<description summary="manager to create per-output power management">
|
||||||
|
This interface is a manager that allows creating per-output power
|
||||||
|
management mode controls.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="get_output_power">
|
||||||
|
<description summary="get a power management for an output">
|
||||||
|
Create an output power management mode control that can be used to
|
||||||
|
adjust the power management mode for a given output.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
|
||||||
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the manager">
|
||||||
|
All objects created by the manager will still remain valid, until their
|
||||||
|
appropriate destroy request has been called.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_power_v1" version="1">
|
||||||
|
<description summary="adjust power management mode for an output">
|
||||||
|
This object offers requests to set the power management mode of
|
||||||
|
an output.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="mode">
|
||||||
|
<entry name="off" value="0"
|
||||||
|
summary="Output is turned off."/>
|
||||||
|
<entry name="on" value="1"
|
||||||
|
summary="Output is turned on, no power saving"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="set_mode">
|
||||||
|
<description summary="Set an outputs power save mode">
|
||||||
|
Set an output's power save mode to the given mode. The mode change
|
||||||
|
is effective immediately. If the output does not support the given
|
||||||
|
mode a failed event is sent.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="mode">
|
||||||
|
<description summary="Report a power management mode change">
|
||||||
|
Report the power management mode change of an output.
|
||||||
|
|
||||||
|
The mode event is sent after an output changed its power
|
||||||
|
management mode. The reason can be a client using set_mode or the
|
||||||
|
compositor deciding to change an output's mode.
|
||||||
|
This event is also sent immediately when the object is created
|
||||||
|
so the client is informed about the current power management mode.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="uint" enum="mode"
|
||||||
|
summary="the output's new power management mode"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="failed">
|
||||||
|
<description summary="object no longer valid">
|
||||||
|
This event indicates that the output power management mode control
|
||||||
|
is no longer valid. This can happen for a number of reasons,
|
||||||
|
including:
|
||||||
|
- The output doesn't support power management
|
||||||
|
- Another client already has exclusive power management mode control
|
||||||
|
for this output
|
||||||
|
- The output disappeared
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy this power management">
|
||||||
|
Destroys the output power management mode control object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
Reference in New Issue
Block a user