Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eeb18679e6 | |||
| 2046adfc79 | |||
| bb8709bdf5 | |||
| 212a6ab426 | |||
| 2622d514c4 | |||
| b8d94b271f | |||
| 7c3cd04c1b | |||
| 6d502ea67e | |||
| 165879eb0d | |||
| ed851b0eed | |||
| 6abaf515ae | |||
| b972354e97 | |||
| dec5642e26 | |||
| 310d396407 | |||
| 4594b55bf4 | |||
| d1581e866f | |||
| c50b5e1ce9 | |||
| bbda532246 | |||
| ead2b06eca | |||
| db0a3b1655 | |||
| 180f571018 | |||
| 707453a513 | |||
| 21c91b0b9c | |||
| b32a63d9b4 | |||
| a9636a4112 | |||
| 18af7036bb | |||
| 310d31e98d | |||
| 6a3995f69a |
8
README
8
README
@@ -1,7 +1,15 @@
|
|||||||
Install
|
Install
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
|
- controldeck
|
||||||
|
- python package justpy, the framework: pip install justpy --upgrade
|
||||||
- (optionally) for volume buttons: libpulse
|
- (optionally) for volume buttons: libpulse
|
||||||
|
- controldeck-gui
|
||||||
|
- render engine
|
||||||
|
- GTK: python-gobject, python-cairo, webkit2gtk>=2.22
|
||||||
|
- QT: qt5-webkit, python-qtpy
|
||||||
|
- QT5: python-pyqt5-webengine, python-pyqt5
|
||||||
|
- QT: pyside2, pyside6
|
||||||
|
|
||||||
local:
|
local:
|
||||||
./setup.sh
|
./setup.sh
|
||||||
|
|||||||
1635
controldeck.py
1635
controldeck.py
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
from tkinter import Tk, messagebox
|
from tkinter import Tk, messagebox
|
||||||
from webview import create_window, start
|
import webview
|
||||||
from controldeck import config_load, process
|
from controldeck import config_load, process
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -14,20 +14,73 @@ def thread_function(name):
|
|||||||
# print("Thread %s: finishing", name)
|
# print("Thread %s: finishing", name)
|
||||||
# p = process("xdotool search --name 'ControlDeck'")
|
# p = process("xdotool search --name 'ControlDeck'")
|
||||||
# intersection of ControlDeck window name and empty classname
|
# intersection of ControlDeck window name and empty classname
|
||||||
p = process("comm -12 <(xdotool search --name 'ControlDeck' | sort) <(xdotool search --classname '^$' | sort)")
|
p = process("comm -12 <(xdotool search --name 'ControlDeck' | sort) <(xdotool search --classname '^$' | sort)", shell=True)
|
||||||
if p:
|
if p:
|
||||||
# print(p)
|
# print(p)
|
||||||
# process("xdotool search --name 'ControlDeck' set_window --class 'controldeck'", output=False)
|
# process("xdotool search --name 'ControlDeck' set_window --class 'controldeck'", output=False)
|
||||||
# process("xdotool search --name 'ControlDeck' set_window --classname 'controldeck' --class 'ControlDeck' windowunmap windowmap", output=False) # will find to many wrong ids
|
# process("xdotool search --name 'ControlDeck' set_window --classname 'controldeck' --class 'ControlDeck' windowunmap windowmap", output=False) # will find to many wrong ids
|
||||||
process(f"xdotool set_window --classname 'controldeck' --class 'ControlDeck' {p} windowunmap {p} windowmap {p}", output=False)
|
process(f"xdotool set_window --classname 'controldeck' --class 'ControlDeck' {p} windowunmap {p} windowmap {p}", shell=True, output=False)
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
def main(args, pid=-1):
|
def main(args, pid=-1):
|
||||||
|
config = config_load(conf=args.config)
|
||||||
|
host = config.get('default', 'host', fallback='0.0.0.0')
|
||||||
|
port = config.get('default', 'port', fallback='8000')
|
||||||
|
url = f"http://{host}:{port}/?gui&pid={str(pid)}"
|
||||||
|
try:
|
||||||
|
width = config.getint('gui', 'width', fallback=800)
|
||||||
|
except ValueError as e:
|
||||||
|
width = 800
|
||||||
|
print(f"Error width: {e}. fallback to: {width}")
|
||||||
|
try:
|
||||||
|
height = config.getint('gui', 'height', fallback=600)
|
||||||
|
except ValueError as e:
|
||||||
|
width = 600
|
||||||
|
print(f"Error height: {e}. fallback to {width}")
|
||||||
|
try:
|
||||||
|
x = config.getint('gui', 'x', fallback='')
|
||||||
|
except ValueError as e:
|
||||||
|
x = None
|
||||||
|
print(f"Error x: {e}. fallback to {x}")
|
||||||
|
try:
|
||||||
|
y = config.getint('gui', 'y', fallback='')
|
||||||
|
except ValueError as e:
|
||||||
|
y = None
|
||||||
|
print(f"Error y: {e}. fallback to: {y}")
|
||||||
|
resizable = config.get('gui', 'resizable', fallback='True').title() == 'True'
|
||||||
|
fullscreen = config.get('gui', 'fullscreen', fallback='False').title() == 'True'
|
||||||
|
try:
|
||||||
|
min_width = config.getint('gui', 'min_width', fallback=200)
|
||||||
|
except ValueError as e:
|
||||||
|
min_width = 200
|
||||||
|
print(f"Error min_width: {e}. fallback to: {min_width}")
|
||||||
|
try:
|
||||||
|
min_height = config.getint('gui', 'min_height', fallback=100)
|
||||||
|
except ValueError as e:
|
||||||
|
min_height = 100
|
||||||
|
print(f"Error min_height: {e}. fallback to: {min_height}")
|
||||||
|
min_size = (min_width, min_height)
|
||||||
|
frameless = config.get('gui', 'frameless', fallback='False').title() == 'True'
|
||||||
|
minimized = config.get('gui', 'minimized', fallback='False').title() == 'True'
|
||||||
|
maximized = config.get('gui', 'maximized', fallback='False').title() == 'True'
|
||||||
|
on_top = config.get('gui', 'always_on_top', fallback='False').title() == 'True'
|
||||||
|
confirm_close = config.get('gui', 'confirm_close', fallback='False').title() == 'True'
|
||||||
|
transparent = config.get('gui', 'transparent', fallback='True').title() == 'True'
|
||||||
|
gui_type = config.get('gui', 'gui_type', fallback=None)
|
||||||
|
gui_type = gui_type if gui_type != "" else None
|
||||||
|
menu = config.get('gui', 'menu', fallback='True').title() == 'True'
|
||||||
|
if args.debug:
|
||||||
|
print(f"config file [default]: {config.items('default')}")
|
||||||
|
print(f"config file [gui]: {config.items('gui')}")
|
||||||
|
|
||||||
#controldeck_process = process("ps --no-headers -C controldeck")
|
#controldeck_process = process("ps --no-headers -C controldeck")
|
||||||
controldeck_process = process("ps --no-headers -C controldeck || ps aux | grep -e 'python.*controldeck.py' | grep -v grep")
|
controldeck_process = process("ps --no-headers -C controldeck || ps aux | grep -e 'python.*controldeck.py' | grep -v grep", shell=True, output=True)
|
||||||
|
|
||||||
if args.start and controldeck_process == "":
|
if args.start and controldeck_process == "":
|
||||||
process("controldeck &", output=False)
|
cmd = "controldeck"
|
||||||
|
cmd += " --config={args.config}" if args.config else ""
|
||||||
|
print(cmd)
|
||||||
|
process(cmd, shell=True, output=False)
|
||||||
|
|
||||||
elif controldeck_process == "":
|
elif controldeck_process == "":
|
||||||
# cli output
|
# cli output
|
||||||
@@ -42,46 +95,8 @@ def main(args, pid=-1):
|
|||||||
|
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
config = config_load(conf=args.config)
|
window = webview.create_window(
|
||||||
url = config.get('gui', 'url', fallback='http://0.0.0.0:8000') + "/?gui&pid=" + str(pid)
|
title="ControlDeck",
|
||||||
try:
|
|
||||||
width = int(config.get('gui', 'width', fallback=800))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{e}")
|
|
||||||
width = 800
|
|
||||||
try:
|
|
||||||
height = int(config.get('gui', 'height', fallback=600))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{e}")
|
|
||||||
width = 600
|
|
||||||
try:
|
|
||||||
x = int(config.get('gui', 'x', fallback=''))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{e}")
|
|
||||||
x = None
|
|
||||||
try:
|
|
||||||
y = int(config.get('gui', 'y', fallback=''))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{e}")
|
|
||||||
y = None
|
|
||||||
resizable = config.get('gui', 'resizable', fallback='True').title() == 'True'
|
|
||||||
fullscreen = config.get('gui', 'fullscreen', fallback='False').title() == 'True'
|
|
||||||
try:
|
|
||||||
min_width = int(config.get('gui', 'min_width', fallback=200))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{e}")
|
|
||||||
min_width = 200
|
|
||||||
try:
|
|
||||||
min_height = int(config.get('gui', 'min_height', fallback=100))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{e}")
|
|
||||||
min_width = 100
|
|
||||||
min_size = (min_width, min_height)
|
|
||||||
frameless = config.get('gui', 'frameless', fallback='False').title() == 'True'
|
|
||||||
minimized = config.get('gui', 'minimized', fallback='False').title() == 'True'
|
|
||||||
on_top = config.get('gui', 'always_on_top', fallback='False').title() == 'True'
|
|
||||||
|
|
||||||
create_window("ControlDeck",
|
|
||||||
url=url,
|
url=url,
|
||||||
html=None,
|
html=None,
|
||||||
js_api=None,
|
js_api=None,
|
||||||
@@ -89,21 +104,92 @@ def main(args, pid=-1):
|
|||||||
height=height,
|
height=height,
|
||||||
x=x,
|
x=x,
|
||||||
y=y,
|
y=y,
|
||||||
|
screen=None,
|
||||||
resizable=resizable,
|
resizable=resizable,
|
||||||
fullscreen=fullscreen,
|
fullscreen=fullscreen,
|
||||||
min_size=min_size,
|
min_size=min_size,
|
||||||
hidden=False,
|
hidden=False,
|
||||||
frameless=frameless,
|
frameless=frameless,
|
||||||
easy_drag=True,
|
easy_drag=True,
|
||||||
|
focus=True,
|
||||||
minimized=minimized,
|
minimized=minimized,
|
||||||
|
maximized=maximized,
|
||||||
on_top=on_top,
|
on_top=on_top,
|
||||||
confirm_close=False,
|
confirm_close=confirm_close,
|
||||||
background_color='#000000',
|
background_color='#000000',
|
||||||
transparent=True,
|
transparent=transparent, # TODO: bug in qt; menu bar is transparent
|
||||||
text_select=False)
|
text_select=False,
|
||||||
|
zoomable=False, # zoom via js
|
||||||
|
draggable=False,
|
||||||
|
vibrancy=False,
|
||||||
|
localization=None,
|
||||||
|
)
|
||||||
x = threading.Thread(target=thread_function, args=(1,))
|
x = threading.Thread(target=thread_function, args=(1,))
|
||||||
x.start()
|
x.start()
|
||||||
start()
|
|
||||||
|
def menu_reload():
|
||||||
|
window = webview.active_window()
|
||||||
|
if window:
|
||||||
|
url = window.get_current_url()
|
||||||
|
window.load_url(url)
|
||||||
|
print(window.get_current_url())
|
||||||
|
print(window)
|
||||||
|
print(dir(window))
|
||||||
|
def menu_zoomin():
|
||||||
|
window = webview.active_window()
|
||||||
|
if window:
|
||||||
|
zoom = window.evaluate_js('document.documentElement.style.zoom')
|
||||||
|
if zoom == "":
|
||||||
|
zoom = 1.0
|
||||||
|
else:
|
||||||
|
zoom = float(zoom)
|
||||||
|
zoom += 0.1
|
||||||
|
print(f"zoom-in: {zoom}")
|
||||||
|
window.evaluate_js(f'document.documentElement.style.zoom = {zoom}')
|
||||||
|
print(f"set document.documentElement.style.zoom = {zoom}")
|
||||||
|
def menu_zoomout():
|
||||||
|
window = webview.active_window()
|
||||||
|
if window:
|
||||||
|
zoom = window.evaluate_js('document.documentElement.style.zoom')
|
||||||
|
if zoom == "":
|
||||||
|
zoom = 1.0
|
||||||
|
else:
|
||||||
|
zoom = float(zoom)
|
||||||
|
zoom -= 0.1
|
||||||
|
print(f"zoom-out: {zoom}")
|
||||||
|
window.evaluate_js(f'document.documentElement.style.zoom = {zoom}')
|
||||||
|
print(f"set document.documentElement.style.zoom = {zoom}")
|
||||||
|
def menu_zoomreset():
|
||||||
|
window = webview.active_window()
|
||||||
|
if window:
|
||||||
|
zoom = 1.0
|
||||||
|
print(f"zoom-reset: {zoom}")
|
||||||
|
window.evaluate_js(f'document.documentElement.style.zoom = {zoom}')
|
||||||
|
print(f"set document.documentElement.style.zoom = {zoom}")
|
||||||
|
menu_items = []
|
||||||
|
if menu:
|
||||||
|
menu_items = [webview.menu.Menu(
|
||||||
|
'Main', [
|
||||||
|
webview.menu.MenuAction('Reload', menu_reload),
|
||||||
|
webview.menu.MenuAction('zoom +', menu_zoomin),
|
||||||
|
webview.menu.MenuAction('zoom -', menu_zoomout),
|
||||||
|
webview.menu.MenuAction('zoom reset', menu_zoomreset),
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
# TODO: zoom reset on reload (both from menu and within justpy)
|
||||||
|
# TODO: add zoom in config
|
||||||
|
# TODO: move zoom logic to justpy but then it is fix for all,
|
||||||
|
# maybe better a zoom argument in url address
|
||||||
|
|
||||||
|
def win_func(window):
|
||||||
|
print(window.get_current_url())
|
||||||
|
webview.start(
|
||||||
|
func=win_func,
|
||||||
|
args=window,
|
||||||
|
gui=gui_type, # TODO: bug in qt; any menu action is always the last action
|
||||||
|
debug=args.debug,
|
||||||
|
menu=menu_items,
|
||||||
|
)
|
||||||
|
|
||||||
def cli():
|
def cli():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=ControlDeck
|
Description=ControlDeck
|
||||||
ConditionFileIsExecutable=/usr/bin/controldeck
|
ConditionFileIsExecutable=/usr/bin/controldeck
|
||||||
After=network.target
|
After=systemd-user-sessions.service getty@tty1.service plymouth-quit.service systemd-logind.service network.target
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
|
# add a pause to assure /etc/X11/xinit/xinitrc.d/50-systemd-user.sh to run
|
||||||
|
# this will add DISPLAY and XAUTHORITY env
|
||||||
|
# ExecStartPre=/bin/sleep 5
|
||||||
|
ExecStartPre=/bin/sh -c '(while test ! -v DISPLAY -o ! -v XAUTHORITY; do echo "wait for DISPLAY and XAUTHORITY"; sleep 2; done; echo "DISPLAY and XAUTHORITY found");'
|
||||||
|
# allowed time for the start
|
||||||
TimeoutStartSec=30
|
TimeoutStartSec=30
|
||||||
ExecStartPre=/bin/sh -c 'source /etc/profile'
|
ExecStart=/usr/bin/controldeck -D
|
||||||
ExecStart=/usr/bin/controldeck
|
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=4
|
RestartSec=4
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=default.target
|
#WantedBy=default.target
|
||||||
|
WantedBy=graphical-session.target
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ After=network.target
|
|||||||
[Service]
|
[Service]
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
TimeoutStartSec=30
|
TimeoutStartSec=30
|
||||||
ExecStartPre=/bin/sh -c 'source /etc/profile'
|
#ExecStartPre=/bin/sh -c 'source /etc/profile'
|
||||||
ExecStart=%h/.local/bin/controldeck
|
ExecStart=%h/.local/bin/controldeck -D
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=4
|
RestartSec=4
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
|
|||||||
@@ -1,59 +1,73 @@
|
|||||||
# Examples:
|
# Examples:
|
||||||
#
|
#
|
||||||
# [N.volume.NAME]
|
# [TAB:N.empty.NAME]
|
||||||
# name = sink_name
|
# : TAB optional tab name to specify tab group
|
||||||
# color-fg = hex color code
|
|
||||||
# color-bg = hex color code
|
|
||||||
#
|
|
||||||
# : N. optional number to specify group/row
|
# : N. optional number to specify group/row
|
||||||
# : NAME id, name of the button
|
# : NAME id of the empty spot
|
||||||
# : name sink name, see name with either:
|
#
|
||||||
|
# [TAB:N.label.NAME]
|
||||||
|
# : TAB optional tab name to specify tab group
|
||||||
|
# : N. optional number to specify group/row
|
||||||
|
# : NAME id, name of the label
|
||||||
|
#
|
||||||
|
# [TAB:N.sink.NAME]
|
||||||
|
# : TAB optional tab name to specify tab group
|
||||||
|
# : N. optional number to specify group/row
|
||||||
|
# : NAME sink id name, see name with either:
|
||||||
# pactl list sinks short
|
# pactl list sinks short
|
||||||
# pamixer --list-sinks
|
# pamixer --list-sinks
|
||||||
# : color-bg background color
|
# description = text for the sink
|
||||||
# : color-bg forground color
|
|
||||||
#
|
#
|
||||||
# [N.button.NAME]
|
# [TAB:N.source.NAME]
|
||||||
# text-alt = name
|
# : TAB optional tab name to specify tab group
|
||||||
# color-fg = hex color code
|
# : N. optional number to specify group/row
|
||||||
# color-bg = hex color code
|
# : NAME source id name, see name with either:
|
||||||
# command = shell command
|
# pactl list sources short
|
||||||
# second command
|
# pamixer --list-sources
|
||||||
# ...
|
# description = text for the source
|
||||||
# command-alt = shell command ...
|
|
||||||
# state = normal state
|
|
||||||
# state-command = shell command ...
|
|
||||||
# icon = Font Awesome
|
|
||||||
# icon-alt = Font Awesom
|
|
||||||
# image = path to svg file
|
|
||||||
# image-alt = path to svg file
|
|
||||||
#
|
#
|
||||||
|
# [TAB:N.sink-inputs]
|
||||||
|
# : TAB optional tab name to specify tab group
|
||||||
|
# : N. optional number to specify group/row
|
||||||
|
#
|
||||||
|
# [TAB:N.button.NAME]
|
||||||
|
# : TAB optional tab name to specify tab group
|
||||||
# : N. optional group/row specification
|
# : N. optional group/row specification
|
||||||
# : NAME id, name of the button
|
# : NAME id, name of the button
|
||||||
# : text-alt optional alternative button text
|
# text-alt = optional alternative burron text
|
||||||
# : color-bg background color
|
# color-fg = foreground color as hex color code, e.g. #aa5500
|
||||||
# : color-bg forground color
|
# color-bg = background color as hex color code, e.g. #0055aa
|
||||||
# : command command(s) to run
|
# command = command(s) to run, seperated by new lines: shell command
|
||||||
# : command-alt optional back-switch command(s) to run
|
# second command ...
|
||||||
# : state string to define the normal state
|
# command-alt = optinal back-switch command(s) to run: shell command ...
|
||||||
# : state-command command to get the state
|
# state-alt = string to define the alternative state (pressed)
|
||||||
# : icon use icon instead of NAME (Font Awesome), e.g.: fas fa-play
|
# state-command = command to get the state: shell command ...
|
||||||
# : icon-alt optional alternative icon
|
# icon = add icon in front of NAME, e.g. fas fa-play
|
||||||
# : image absolute path to svg file
|
# icon-alt = optional alternative icon
|
||||||
# : image-alt optional alternative image
|
# image = absolte path to image file (svg, png)
|
||||||
#
|
# image-alt = optional alternative absolue path to image file
|
||||||
# [N.empty.NAME]
|
|
||||||
#
|
# [TAB:N.slider.NAME]
|
||||||
# : N. optional number to specify group/row
|
# : TAB optional tab name to specify tab group
|
||||||
|
# : N. optional group/row specification
|
||||||
# : NAME id, name of the button
|
# : NAME id, name of the button
|
||||||
|
# description = text for the slider
|
||||||
|
# icon = add icon in front of slider, e.g. tune
|
||||||
|
# min = minimum int value, e.g. 0
|
||||||
|
# max = maximum int value, e.g. 100
|
||||||
|
# step = step size, e.g. 1
|
||||||
|
# state-command = command to get the state: shell command
|
||||||
|
# command = command to run to get the value, using {value} in the command to
|
||||||
|
# interpolate the value: shell command
|
||||||
|
|
||||||
[default]
|
[default]
|
||||||
|
host = 0.0.0.0
|
||||||
|
port = 8000
|
||||||
# status = False
|
# status = False
|
||||||
# volume-decrease-icon = fas fa-volume-down
|
# volume-decrease-icon = fas fa-volume-down
|
||||||
# volume-increase-icon = fas fa-volume-up
|
# volume-increase-icon = fas fa-volume-up
|
||||||
# volume-mute-icon = fas fa-volume-off
|
# volume-mute-icon = fas fa-volume-off
|
||||||
# volume-mute-icon-alt = fas fa-volume-mute
|
# volume-mute-icon-alt = fas fa-volume-mute
|
||||||
# volume-mute-icon-alt =
|
|
||||||
# volume-decrease-image =
|
# volume-decrease-image =
|
||||||
# volume-increase-image =
|
# volume-increase-image =
|
||||||
# volume-mute-image =
|
# volume-mute-image =
|
||||||
@@ -68,7 +82,6 @@
|
|||||||
# mic-mute-image-alt =
|
# mic-mute-image-alt =
|
||||||
|
|
||||||
[gui]
|
[gui]
|
||||||
url = http://0.0.0.0:8000
|
|
||||||
width = 800
|
width = 800
|
||||||
height = 600
|
height = 600
|
||||||
# x and y specifying the window coordinate (empty = centered)
|
# x and y specifying the window coordinate (empty = centered)
|
||||||
@@ -80,7 +93,13 @@ min_width = 200
|
|||||||
min_height = 100
|
min_height = 100
|
||||||
frameless = False
|
frameless = False
|
||||||
minimized = False
|
minimized = False
|
||||||
|
maximized = False
|
||||||
always_on_top = False
|
always_on_top = False
|
||||||
|
confirm_close = False
|
||||||
|
transparent = True
|
||||||
|
# gui_type: qt, gtk, cef, mshtml, edgechromium. or set env PYWEBVIEW_GUI
|
||||||
|
gui_type =
|
||||||
|
menu = True
|
||||||
|
|
||||||
[4.button.Test]
|
[4.button.Test]
|
||||||
command = notify-send -a foo baz
|
command = notify-send -a foo baz
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ version = file: VERSION
|
|||||||
install_requires =
|
install_requires =
|
||||||
justpy
|
justpy
|
||||||
pywebview
|
pywebview
|
||||||
cairosvg
|
|
||||||
py_modules =
|
py_modules =
|
||||||
controldeck
|
controldeck
|
||||||
controldeck_gui
|
controldeck_gui
|
||||||
|
|
||||||
[options.entry_points]
|
[options.entry_points]
|
||||||
console_scripts =
|
console_scripts =
|
||||||
controldeck = controldeck:main
|
controldeck = controldeck:cli
|
||||||
controldeck-gui = controldeck_gui:cli
|
controldeck-gui = controldeck_gui:cli
|
||||||
|
|||||||
Reference in New Issue
Block a user