stemsee wrote:OK.....I should read the manpage ... finally!
Noooo! Don't do it! If my calculations are correct, there is 89% chance you'll cause a blizzard via butterfly effect...
https://en.wikipedia.org/wiki/Butterfly_effect
here's a video of my fancy yad alarm with at command:
https://www.youtube.com/watch?v=KGNV2cLfF_I
It is designed for xfce since I use the fake window bar.
Nothing special with move/resize buttons: on click "xdotool key alt+F7" and alt+F8 respectively.
I'm not sure what keyboard combinations other window managers use to move windows.
However, Minimize, Maximize and Close should work with all wm's.
If not remove them and remove '--undecorate' option in the main dialog.
Since at command is used alarm will open after restart.
I borrowed a few lines from Fredx's script.
Requires: at, xfce4, wmctrl, xdotool, yad 0.42 (with html dialog), mpv
So install what is needed.
You can choose between running the file in mpv or a custom command.
If you type in custom command, don't use "@" character. This is the limitation.
Custom command can be
firefox "www.youtube.com" for example.
Leave the custom blank for mpv.
Ticking "Loop forever" overides "repeat".
Job can be listed and removed via "List at Job" button.
Any open child windows will be killed after the main window is closed.
I've (ab)used DOM2 events in JavaScript to create a link and emulate mouseclick on that link to make yad to print the output.
Code: Select all
#!/bin/bash
# Fancy alarm Misko_2083 @ 2020
# Requires: at, xfce4, wmctrl, xdotool, yad 0.42 (with html dialog), mpv
#########################
# Begin User Interface #
#########################
# JavaScript, HTML and CSS
YURI="$(cat << EOF
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--CSS for the page-->
<style>
.body, .html {
overflow-y: hidden;
cursor: default;
background-color: #CECECE;
}
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
top: 180%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 1s;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent black transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
}
#jsalarmclock{
font-weight: bold;
font-size: 14px;
}
#jsalarmclock div{
margin-bottom: 0.8em;
}
#jsalarmclock div.leftcolumn{
float: left;
width: 150px;
font-size: 14px;
clear: left;
}
#jsalarmclock span{
margin-right: 10px;
}
#jsalarmclock input[type=number]{
width: 50px;
}
p {
font-weight: bold;
font-size: 11px;
}
.btn {
border: 2px solid black;
background-color: white;
color: black;
padding: 8px 16px;
position: sticky;
font-size: 12px;
cursor: default;
}
/* Green */
.bar {
border-color: #4CAF50;
color: green;
text-decoration: none;
}
.bar:hover {
background-color: #4CAF50;
color: white;
}
/* Blue */
.bl {
border-color: #2196F3;
color: dodgerblue;
text-decoration: none;
}
.bl:hover {
background: #2196F3;
color: white;
text-decoration: none;
}
/* Orange */
.bltop {
border-color: #ff9800;
color: orange;
text-decoration: none;
}
.bltop:hover {
background: #ff9800;
color: white;
text-decoration: none;
}
/* Red */
.restart{
border-color: #f44336;
color: red;
text-decoration: none;
}
.restart:hover {
background: #f44336;
color: white;
}
/* Gray */
.default {
border-color: #000000;
color: black;
text-decoration: none;
}
.default:hover {
background: #000000;
color: white;
text-decoration: none;
}
.title {
font-size: 10px
cursor: default;
}
</style>
<!--Script to prevent right click menu-->
<script type="text/javascript">
if (document.addEventListener) { // IE >= 9; other browsers
document.addEventListener('contextmenu', function(e) {
//here you do nothing
e.preventDefault();
}, false);
} else { // IE < 9
document.attachEvent('oncontextmenu', function() {
alert("You've tried to open context menu");
window.event.returnValue = false;
});
}
</script>
<script type="text/javascript">
/***********************************************
* JavaScript Alarm Clock- by JavaScript Kit (www.javascriptkit.com)
* This notice must stay intact for usage
* Visit JavaScript Kit at http://www.javascriptkit.com/ for this script and 100s more
***********************************************/
/* Modified for my needs Misko_2083 */
var jsalarm={
padfield:function(f){
return (f<10)? "0"+f : f
},
showcurrenttime:function(){
var dateobj=new Date()
var ct=this.padfield(dateobj.getHours())+":"+this.padfield(dateobj.getMinutes())+":"+this.padfield(dateobj.getSeconds())
this.ctref.innerHTML=ct
this.ctref.setAttribute("title", ct)
},
init:function(){
var dateobj=new Date()
this.ctref=document.getElementById("jsalarm_ct")
this.submitref=document.getElementById("submitbutton")
this.submitref.onclick=function(){
jsalarm.setalarm()
//this.value="Alarm Set"
this.disabled=false
return false
}
var selections=document.getElementsByTagName("select")
this.hourselect=selections[0]
this.minuteselect=selections[1]
for (var i=0; i<60; i++){
if (i<24) //If still within range of hours field: 0-23
this.hourselect[i]=new Option(this.padfield(i), this.padfield(i), false, dateobj.getHours()==i)
this.minuteselect[i]=new Option(this.padfield(i), this.padfield(i), false, dateobj.getMinutes()+1==i)
}
jsalarm.showcurrenttime()
jsalarm.timer=setInterval(function(){jsalarm.showcurrenttime()}, 1000)
},
info:function(a) {
var h = document.createElement("p");
var filename = String(a).replace(/^.*[\\\/]/, '');
var t = document.createTextNode("Alarm "+filename);
h.appendChild(t);
document.body.appendChild(h);
h.setAttribute("id", "info");
},
dom:function(a){
// DOM 2 Events
var dispatchMouseEvent = function(target, var_args) {
var e = document.createEvent("MouseEvents");
// If you need clientX, clientY, etc., you can call
// initMouseEvent instead of initEvent
e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1));
target.dispatchEvent(e);
};
dispatchMouseEvent(a, 'mouseover', true, true);
dispatchMouseEvent(a, 'mousedown', true, true);
dispatchMouseEvent(a, 'click', true, true);
dispatchMouseEvent(a, 'mouseup', true, true);
},
setalarm:function(){
this.hourwake=this.hourselect.options[this.hourselect.selectedIndex].value
this.minutewake=this.minuteselect.options[this.minuteselect.selectedIndex].value
var a = document.createElement('a');
var linkText = document.createTextNode("Go");
a.appendChild(linkText);
a.title = "fake link";
a.href = this.hourselect.options[this.hourselect.selectedIndex].value+":"+this.minuteselect.options[this.minuteselect.selectedIndex].value;
jsalarm.dom(a)
jsalarm.info(a)
a.href = "repeat@"+document.getElementById("repeat").value;
jsalarm.dom(a)
if(document.getElementById("forever").checked == true) {
a.href = "repeat@"+document.getElementById("forever").value;
jsalarm.dom(a)
}
a.href = "command@"+document.getElementById("command").value;
jsalarm.dom(a)
//a.parentNode.removeChild(linkText);
//this.hourselect.disabled=true
//this.minuteselect.disabled=true
}
}
</script>
</head>
<body class="body">
<!--left-->
<div
style="-moz-user-select: none; -webkit-user-select: none; -ms-user-select:none; user-select:none;-o-user-select:none;position:absolute;left:0;"
unselectable="on"
onselectstart="return false;"
onmousedown="return false;">
<div class="tooltip">
<a href="move" class="btn default">#</a>
<span class="tooltiptext">Move</span>
</div>
<text class="title"> Alarm </text>
</div>
<!--right-->
<div
style="-moz-user-select: none; -webkit-user-select: none; -ms-user-select:none; user-select:none;-o-user-select:none;position:absolute;right:0;"
unselectable="on"
onselectstart="return false;"
onmousedown="return false;">
<!--Here you define window button links and text-->
<div class="tooltip">
<a href="resize" class="btn bar">+</a>
<span class="tooltiptext">Resize</span>
</div>
<div class="tooltip">
<a href="minimize" class="btn bltop">_</a>
<span class="tooltiptext">Minimize</span>
</div>
<div class="tooltip">
<a href="maximize" class="btn bl">[]</a>
<span class="tooltiptext">Maximize</span>
</div>
<a href="exit" class="btn restart">X</a>
</div>
<br />
<br />
<form action="" method="">
<div id="jsalarmclock">
<div><div class="leftcolumn">Current Time:</div> <span id="jsalarm_ct" style="letter-spacing: 2px"></span></div>
<div><div class="leftcolumn">Set Alarm:</div> <span><select></select> Hour</span> <span><select></select> Minutes</span> </div>
<div><div class="leftcolumn">Repeat:</div><input size="5" type="number" id="repeat" min="1" value="1"/> <br>
<div class="leftcolumn">Loop forever</div> <input type="checkbox" id="forever" value="forever"/>
<span style="font: normal 11px Tahoma">Loop forever overides repeat</span> <br>
<div><div class="leftcolumn">Set file:</div><a href="file:///musicfile@"><button type="button">Select a file to play</button></a>
<span style="font: normal 11px Tahoma">Select a file to run with mpv or type in a custom action</span></div>
<div><div class="leftcolumn">Set Custom Action:</div> <input type="text" id="command" size="55" value="" /> <br>
<span style="font: normal 11px Tahoma">*Command to launch, if empty mpv will be used (do not use "@" character here)</span></div>
<input type="submit" value="Set Alarm!" id="submitbutton" />
</div>
</form>
<a href="file:///atq@"><button type="button">At Job List</button></a>
<script type="text/javascript">
jsalarm.init()
</script>
</body>
</html>
EOF
)"
#########################
# End of User interface #
#########################
#########################
# Bash functions #
#########################
# fuction to recursively kill all descendants
function _kill_descendant_processes() {
local pid="$1"
local and_self="${2:-false}"
if children="$(pgrep -P "$pid")"; then
for child in $children; do
_kill_descendant_processes "$child" true
done
fi
if [[ "$and_self" == true ]]; then
kill -SIGTERM "$pid"
fi
}
# Main window
function _yad_ui(){
# Set the line buffering with stdbuf
echo "${YURI}" | stdbuf -oL -eL yad --title="Set Alarm" --width=650 --height=500 --no-escape \
--html --no-buttons --print-uri --undecorated --borders=0 --window-icon="alarm1c.png" 2>&1 & echo $!
}
# Main Function
function _do_stuff(){
# fetch yad process id
read YAD_PID
# read yad stdout line by line
while read -r line
do
case ${line##*/} in
resize) xdotool key alt+F8 ;;
move) xdotool key alt+F7 ;;
exit) if yad --width=400 --title="Set Alarm" --height=100 --text="Exit?" --button="No:1" --button="Yes:0" --window-icon="alarm1c.png" 2>/dev/null; then
kill -SIGUSR1 $YAD_PID ;
_kill_descendant_processes $$ 2>/dev/null;
break
fi
;;
minimize) xdotool getactivewindow windowminimize ;;
maximize) if xprop -id $(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2) _NET_WM_STATE | grep -E "MAXIMIZED_HORZ.*MAXIMIZED_VERT|MAXIMIZED_VERT.*MAXIMIZED_HORZ" > /dev/null 2>&1
then
wmctrl -ir $(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2) -b remove,maximized_vert,maximized_horz
else
wmctrl -ir $(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2) -b add,maximized_vert,maximized_horz
fi ;;
[0-9][0-9]:[0-9][0-9]*)
#kill -SIGUSR1 $YAD_PID
echo "Alarm set to: ${line##*/}"
alarm_time="${line##*/}"
;;
repeat@*) REPEAT="$(echo "${line##*@}" | sed 's/%20/ /g')"
;;
command@*) COMMAND="$(echo "${line##*@}" | sed 's/%20/ /g')"
if [ ! -e "/tmp/yalarm.$$" ] ; then
MUSIC="$(yad --width=600 --height=500 \
--title="Alarm" --text="Select a file to play in mpv" \
--file-filter="Audio | *.mp3 *.MP3 *.wav *.WAV *.ogg *.OGG" \
--file 2>/dev/null)"
[ $? != 0 ] && continue
echo "${MUSIC}" > /tmp/yalarm.$$
fi
# Fredx181
hrnow=$(echo $(date +"%k"))
# For when trying to set alarm for next day e.g. from current 21:00 to target 6:00
if [ "${alarm_time%%:*}" -eq "$hrnow" ] && [ "${alarm_time##*:}" -le "$(date +"%M")" ]; then
# prompt yes/no in case accidentally chosen current hour but less than current minute
yad --center --title="Are you sure?" --text="Are you sure to set the alarm to ${alarm_time} - tomorrow ?" --width=400 --button="Yes:0" --button="No:1"
[ $? -ne 0 ] && continue
fi
if [ ! "${COMMAND}" = "" ]; then
at "${alarm_time}" << EOF
exec env DISPLAY="$DISPLAY" $(echo "${line##*@}" | sed 's/%20/ /g') &
EOF
else
if [ "${REPEAT}" = "forever" ]; then
at "${alarm_time}" << EOF
exec env DISPLAY="$DISPLAY" mpv --force-window --loop inf "$(cat /tmp/yalarm.$$)"
EOF
else
at "${alarm_time}" << EOF
exec env DISPLAY="$DISPLAY" mpv --force-window --loop "${REPEAT}" "$(cat /tmp/yalarm.$$)"
EOF
fi
fi
# Here we set alarm
#at "${alarm_time}" << EOF
#exec env DISPLAY="$DISPLAY" $(echo "${line##*@}" | sed 's/%20/ /g')
#EOF
;;
atq@*) (REMOVE_JOB="$(atq | yad --list --width=600 --height=500 \
--text="Select 'at' job to remove or close this window" \
--column "Job List" \
--button="Remove at Job" 2>/dev/null \
| awk '{print $1}')"
if [[ "${REMOVE_JOB}" == [0-9]* ]]; then
echo "${REMOVE_JOB}"
atrm "${REMOVE_JOB}"
killall mpv
fi) &
;;
musicfile@*) (MUSIC="$(yad --width=600 --height=500 \
--title="Alarm" --text="Select a file to play in mpv" \
--file-filter="Audio | *.mp3 *.wav" \
--file 2>/dev/null)" \
[ $? = 0 ] && echo "${MUSIC}" > /tmp/yalarm.$$) &
;;
esac
done
rm /tmp/yalarm.$$
exit
}
_yad_ui | _do_stuff & wait $! 2>/dev/null