Adding shell command execution on click for shell module
This commit is contained in:
parent
fded39fa81
commit
9b2ac5d521
2 changed files with 50 additions and 3 deletions
|
@ -15,6 +15,12 @@ Parameters:
|
||||||
For example shell.command='echo $(date +'%H:%M:%S')'
|
For example shell.command='echo $(date +'%H:%M:%S')'
|
||||||
But NOT shell.command='echo $(date +'%H:%M:%S')'
|
But NOT shell.command='echo $(date +'%H:%M:%S')'
|
||||||
Second one will be evaluated only once at startup
|
Second one will be evaluated only once at startup
|
||||||
|
* shell.left_click_command: Command to execute on
|
||||||
|
left mouse button click. Clicked commands are always
|
||||||
|
executed synchronously.
|
||||||
|
Command formatting rules described above applies here
|
||||||
|
* shell.right_click_command: Command to execute on
|
||||||
|
right mouse button click. See above.
|
||||||
* shell.interval: Update interval in seconds
|
* shell.interval: Update interval in seconds
|
||||||
(defaults to 1s == every bumblebee-status update)
|
(defaults to 1s == every bumblebee-status update)
|
||||||
* shell.async: Run update in async mode. Won't run next thread if
|
* shell.async: Run update in async mode. Won't run next thread if
|
||||||
|
@ -28,19 +34,30 @@ contributed by `rrhuffy <https://github.com/rrhuffy>`_ - many thanks!
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
import functools
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
import core.event
|
||||||
import util.format
|
import util.format
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.get_output))
|
self.widget = core.widget.Widget(self.get_output)
|
||||||
|
super().__init__(config, theme, self.widget)
|
||||||
|
|
||||||
self.__command = self.parameter("command", 'echo "no command configured"')
|
self.__command = self.parameter("command", 'echo "no command configured"')
|
||||||
|
self.__left_click_command = self.parameter(
|
||||||
|
"left_click_command",
|
||||||
|
'echo "no left_click_command configured"')
|
||||||
|
self.__right_click_command = self.parameter(
|
||||||
|
"right_click_command",
|
||||||
|
'echo "no right_click_command configured"')
|
||||||
self.__async = util.format.asbool(self.parameter("async"))
|
self.__async = util.format.asbool(self.parameter("async"))
|
||||||
|
|
||||||
if self.__async:
|
if self.__async:
|
||||||
|
@ -50,9 +67,27 @@ class Module(core.module.Module):
|
||||||
if self.parameter("scrolling.makewide") is None:
|
if self.parameter("scrolling.makewide") is None:
|
||||||
self.set("scrolling.makewide", False)
|
self.set("scrolling.makewide", False)
|
||||||
|
|
||||||
|
if self.__left_click_command is not None:
|
||||||
|
core.input.register(
|
||||||
|
self.widget,
|
||||||
|
button=core.input.LEFT_MOUSE,
|
||||||
|
cmd=functools.partial(
|
||||||
|
self.click_command,
|
||||||
|
command=self.__left_click_command))
|
||||||
|
if self.__right_click_command is not None:
|
||||||
|
core.input.register(
|
||||||
|
self.widget,
|
||||||
|
button=core.input.RIGHT_MOUSE,
|
||||||
|
cmd=functools.partial(
|
||||||
|
self.click_command,
|
||||||
|
command=self.__right_click_command))
|
||||||
|
|
||||||
def set_output(self, value):
|
def set_output(self, value):
|
||||||
self.__output = value
|
self.__output = value
|
||||||
|
|
||||||
|
def click_command(self, event, command=None):
|
||||||
|
util.cli.execute(command, shell=True, ignore_errors=True, wait=True)
|
||||||
|
|
||||||
@core.decorators.scrollable
|
@core.decorators.scrollable
|
||||||
def get_output(self, _):
|
def get_output(self, _):
|
||||||
return self.__output
|
return self.__output
|
||||||
|
@ -60,7 +95,9 @@ class Module(core.module.Module):
|
||||||
def update(self):
|
def update(self):
|
||||||
# if requested then run not async version and just execute command in this thread
|
# if requested then run not async version and just execute command in this thread
|
||||||
if not self.__async:
|
if not self.__async:
|
||||||
self.__output = util.cli.execute(self.__command, shell=True, ignore_errors=True).strip()
|
self.set_output(
|
||||||
|
util.cli.execute(self.__command, shell=True, ignore_errors=True).strip()
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# if previous thread didn't end yet then don't do anything
|
# if previous thread didn't end yet then don't do anything
|
||||||
|
|
|
@ -52,7 +52,17 @@ def execute(
|
||||||
raise RuntimeError("{} not found".format(cmd))
|
raise RuntimeError("{} not found".format(cmd))
|
||||||
|
|
||||||
if wait:
|
if wait:
|
||||||
out, _ = proc.communicate()
|
timeout = 60 # seconds
|
||||||
|
try:
|
||||||
|
out, _ = proc.communicate(timeout=timeout)
|
||||||
|
except subprocess.TimeoutExpired as e:
|
||||||
|
logging.warning(f'''
|
||||||
|
Communication with process pid={proc.pid} hangs for more
|
||||||
|
than {timeout} seconds.
|
||||||
|
If this is not expected, the process is stale, or
|
||||||
|
you might have run in stdout / stderr deadlock.
|
||||||
|
''')
|
||||||
|
out, _ = proc.communicate()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
err = "{} exited with code {}".format(cmd, proc.returncode)
|
err = "{} exited with code {}".format(cmd, proc.returncode)
|
||||||
logging.warning(err)
|
logging.warning(err)
|
||||||
|
|
Loading…
Add table
Reference in a new issue