1#!/usr/local/bin/bash
2
3# a q3-like (or yakuake-like) terminal for arbitrary applications.
4#
5# this lets a new monitor called "q3terminal" scroll in from the top into the
6# current monitor. There the "scratchpad" will be shown (it will be created if
7# it doesn't exist yet). If the monitor already exists it is scrolled out of
8# the screen and removed again.
9#
10# Warning: this uses much resources because herbstclient is forked for each
11# animation step.
12#
13# If a tag name is supplied, this is used instead of the scratchpad
14
15tag="${1:-scratchpad}"
16hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
17
18termwidth_percent=${WIDTH_PERC:-100}
19mrect=( $(hc monitor_rect -p "" ) )
20termwidth=$(( (${mrect[2]} * termwidth_percent) / 100 ))
21termheight=${HEIGHT_PIXELS:-400}
22
23rect=(
24    $termwidth
25    $termheight
26    $(( ${mrect[0]} + (${mrect[2]} - termwidth) / 2 ))
27    $(( ${mrect[1]} - termheight ))
28)
29
30y_line=${mrect[1]}
31
32
33hc add "$tag"
34
35
36monitor=q3terminal
37
38exists=false
39if ! hc add_monitor $(printf "%dx%d%+d%+d" "${rect[@]}") \
40                    "$tag" $monitor 2> /dev/null ; then
41    exists=true
42else
43    # remember which monitor was focused previously
44    hc chain \
45        , new_attr string monitors.by-name."$monitor".my_prev_focus \
46        , substitute M monitors.focus.index \
47            set_attr monitors.by-name."$monitor".my_prev_focus M
48fi
49
50update_geom() {
51    local geom=$(printf "%dx%d%+d%+d" "${rect[@]}")
52    hc move_monitor "$monitor" $geom
53}
54
55steps=${ANIMATION_STEPS:-5}
56interval=${ANIMATION_INTERVAL:-0.01}
57
58animate() {
59    progress=( "$@" )
60    for i in "${progress[@]}" ; do
61        rect[3]=$((y_line - (i * termheight) / steps))
62        update_geom
63        sleep "$interval"
64    done
65}
66
67show() {
68    hc lock
69    hc raise_monitor "$monitor"
70    hc focus_monitor "$monitor"
71    hc unlock
72    hc lock_tag "$monitor"
73    animate $(seq $steps -1 0)
74}
75
76hide() {
77    rect=( $(hc monitor_rect "$monitor" ) )
78    local tmp=${rect[0]}
79    rect[0]=${rect[2]}
80    rect[2]=${tmp}
81    local tmp=${rect[1]}
82    rect[1]=${rect[3]}
83    rect[3]=${tmp}
84    termheight=${rect[1]}
85    y_line=${rect[3]} # height of the upper screen border
86
87    animate $(seq 0 +1 $steps)
88    # if q3terminal still is focused, then focus the previously focused monitor
89    # (that mon which was focused when starting q3terminal)
90    hc substitute M monitors.by-name."$monitor".my_prev_focus \
91        and + compare monitors.focus.name = "$monitor" \
92            + focus_monitor M
93    hc remove_monitor "$monitor"
94}
95
96[ $exists = true ] && hide || show
97
98