Compare commits

...

No commits in common. 'master' and 'gh-pages' have entirely different histories.

@ -1,10 +0,0 @@
name: lint
on: [push, pull_request]
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- name: shellcheck
uses: ludeeus/action-shellcheck@0.1.0

@ -1,24 +0,0 @@
Copyright (c) 2015, Fox Kiester
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -1,15 +0,0 @@
PREFIX ?= /usr/local
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/share/man
LICENSEDIR = $(PREFIX)/share/licenses
install:
# 755 is default
install -D -m 755 tdrop "$(DESTDIR)$(BINDIR)"/tdrop
install -D -m 644 tdrop.1 "$(DESTDIR)$(MANDIR)"/man1/tdrop.1
install -D -m 644 LICENSE "$(DESTDIR)$(LICENSEDIR)"/tdrop/LICENSE
uninstall:
rm -f "$(DESTDIR)$(BINDIR)"/tdrop
rm -f "$(DESTDIR)$(MANDIR)"/man1/tdrop.1
rm -rf "$(DESTDIR)$(LICENSEDIR)/tdrop"

@ -1,5 +0,0 @@
* About
This is a tdrop fork but using an external script xtoolwait (on AUR =xtoolwait-git=).
It was created to support few programs (like suckless tabbed) which doesn't work yet with the upstream version.
Just don't forget to install xtoolwait, because I basically replaced hundred lines of code with just one call to this utility.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

806
tdrop

@ -1,806 +0,0 @@
#!/usr/bin/env bash
MUTDROP_PATH=/tmp/tdrop_"$USER"
# shellcheck disable=SC2174
mkdir -p "$MUTDROP_PATH" -m 700
print_help() {
echo "
usage: tdrop [options] <program> [program options ...]
or 'current'
or one of 'auto_show'/'auto_hide'/'toggle_auto_hide'
or 'hide_all'
options:
-h height specify a height for a newly created term (default: 45%)
-w width specify a width for a newly created term (default: 100%)
-x pos specify x offset for a newly created term (default: 0)
-y pos specify y offset for a newly created term (default: 1, see man)
-s name name for tmux/tmuxinator/tmuxifier session (supported
terminal required)
-n num num or extra text; only needed if for the purpose of using
multiple dropdowns of same program
-c cmd provide a pre-create command
-C cmd provide a post-create command
-l cmd provide a command to float the window before it is mapped
-L cmd provide a command to float the window after it is mapped
-p cmd provide a pre-map command
-P cmd provide a post-map command
-u cmd provide a pre-unmap command -U cmd provide a post-unmap command -d XxY give decoration/border size to accurately restore window
position; only applicable with auto_show
-S cmd can be used to fix saved geometry with auto_hide; see manpage
-i cmd provide a command to detect whether the current window is a
floating window; on applicable with auto_hide
-f flags specify flags/options to be used when creating the term or
window (e.g. -f '--title mytitle'; default: none).
NOTE: This flag is deprecated. Specify flags after the program name
instead. This flag may be removed in the future.
Caution: if there is a tmux session specified (with -s), the option
to execute a program (usually -e for terminal programs) is
implicitly added by tdrop
-a automatically detect window manager and set relevant options
(e.g. this makes specifying -l/-L, -d, and -i uneccessary
for supported WMs) (default: false)
-m for use with multiple monitors and only with dropdowns
(i.e. not for auto_show or auto_hide); convert percentages used
for width or height to values relative to the size of the
current monitor and force resizing of the dropdown when
the monitor changes (default: false)
-t use mouse pointer location for detecting which monitor is the current
one
--wm set the window manager name to mimic another window manager
(for use with -a)
--class name manually specify the class of the window (can be obtained with xprop)
--name name set a new name for the dropdown window
--clear clear saved window id; useful after accidentally make a
window a dropdown (e.g. '$ tdrop --clear current')
--no-cancel don't cancel auto-showing (default is to prevent this when
manually toggling a window after it is auto-hidden)
--timeout set the timeout (in seconds) that tdrop will wait for a window
to appear before giving up in case the program fails to start
(default: 10)
--help print help
See man page for more details.
"
}
error() {
echo >&2 "$@" | tee -a "$MUTDROP_PATH"/log
exit 1
}
# * Default Options and Option Parsing
# xdotool can take percentages; cannot take decimal percentages though
width="100%"
height="45%"
xoff=0
yoff=2
session_name=
num=
pre_create=
post_create=
pre_float=
post_float=
pre_map=
post_map=
pre_unmap=
post_unmap=
dec_fix=
# NOTE:
# pekwm, xfwm4, sawfish, openbox need subtract_when_same to be true
# for awesome, fluxbox, blackbox, mutter, fvwm, and metacity, the value
# does not matter
# set in decoration_settings
subtract_when_same=
is_floating=
program_flags=()
clearwid=false
cancel_auto_show=true
auto_detect_wm=false
monitor_aware=false
pointer_monitor_detection=false
wm=
user_set_wm=false
class=
name=
timeout=10
while getopts :h:w:x:y:s:n:c:C:l:L:p:P:u:U:d:S:i:f:-:amt opt
do
case $opt in
h) height=$OPTARG;;
w) width=$OPTARG;;
x) xoff=$OPTARG;;
y) yoff=$OPTARG;;
s) session_name=$OPTARG;;
n) num=$OPTARG;;
c) pre_create=$OPTARG;;
C) post_create=$OPTARG;;
l) pre_float=$OPTARG;;
L) post_float=$OPTARG;;
p) pre_map=$OPTARG;;
P) post_map=$OPTARG;;
u) pre_unmap=$OPTARG;;
U) post_unmap=$OPTARG;;
d) dec_fix=$OPTARG;;
S) subtract_when_same=false;;
i) is_floating=$OPTARG;;
f) eval "program_flags=($OPTARG)";;
a) auto_detect_wm=true;;
m) monitor_aware=true;;
t) pointer_monitor_detection=true;;
-)
if [[ $OPTARG =~ ^(auto-detect-wm|monitor-aware|pointer-monitor-detection|clear|no-cancel|help)$ ]] || \
[[ $OPTARG == *=* ]]; then
OPTION=${OPTARG%%=*}
OPTARG=${OPTARG#*=}
else
OPTION=$OPTARG
# shellcheck disable=SC2124
OPTARG=${@:$OPTIND:1}
((OPTIND++))
fi
case $OPTION in
height) height=$OPTARG;;
width) width=$OPTARG;;
x-offset) xoff=$OPTARG;;
y-offset) yoff=$OPTARG;;
session) session_name=$OPTARG;;
number) num=$OPTARG;;
pre-create-hook) pre_create=$OPTARG;;
post-create-hook) post_create=$OPTARG;;
pre-map-float-command) pre_float=$OPTARG;;
post-map-float-command) post_float=$OPTARG;;
pre-map-hook) pre_map=$OPTARG;;
post-map-hook) post_map=$OPTARG;;
pre-unmap-hook) pre_unmap=$OPTARG;;
post-unmap-hook) post_unmap=$OPTARG;;
decoration-fix) dec_fix=$OPTARG;;
no-subtract-when-same) subtract_when_same=false;;
is-floating) is_floating=$OPTARG;;
program-flags) eval "program_flags=($OPTARG)";;
auto-detect-wm) auto_detect_wm=true;;
monitor-aware) monitor_aware=true;;
pointer-monitor-detection) pointer_monitor_detection=true;;
wm) wm=$OPTARG
user_set_wm=true;;
class) class=$OPTARG;;
name) name=$OPTARG;;
clear) clearwid=true;;
no-cancel) cancel_auto_show=false;;
timeout) timeout=$OPTARG;;
help) print_help;;
*) error "Unknown option --$OPTION." \
"Use --help to see available flags.";;
esac;;
*) error "Unknown option -$OPTARG." \
"Use --help to see available flags.";;
esac
done
shift "$((OPTIND-1))"
program=$1
if [[ ${#program_flags[@]} -eq 0 ]]; then
program_flags=("${@:2}")
fi
if [[ -z $program ]]; then
error "Program to run is required as a positional argument." \
"For help use -h or --help or see the manpage."
fi
# check that the program is in PATH
if [[ ! $program =~ ^(current|auto_hide|auto_show|toggle_auto_hide|hide_all)$ ]] && \
! type "$program" &> /dev/null; then
error "The program should be in PATH."
fi
# validate options that require number values
if [[ ! $height$width$xoff$yoff =~ ^[0-9%-]*$ ]]; then
error "The -h, -w, -x, and -y values must be numbers (or percentages)."
fi
if [[ -n $dec_fix ]] && [[ ! $dec_fix =~ ^-?[0-9]+x-?[0-9]+$ ]]; then
error "The decoration fix value must have form 'num'x'num'." \
"The numbers can be negative or zero."
fi
# non-user-settable global vars
wid=
# * Multiple Monitor Automatic Re-Sizing
percent_of_total() { # percent total
# gawk "BEGIN {printf(\"%.0f\", 0.01*${1%\%}*$2)}"
echo $((${1%\%} * ${2} / 100))
}
# acts on globals
convert_geometry_to_pixels() {
total_width=$1
total_height=$2
local minus_width minus_height minus_xoff minus_yoff
if [[ $width =~ %$ ]]; then
width=$(percent_of_total "$width" "$total_width")
elif [[ $width =~ ^- ]]; then
minus_width=${width#-}
width=$((total_width-minus_width))
fi
if [[ $height =~ %$ ]]; then
height=$(percent_of_total "$height" "$total_height")
elif [[ $height =~ ^- ]]; then
minus_height=${height#-}
height=$((total_height-minus_height))
fi
if [[ $xoff =~ %$ ]]; then
xoff=$(percent_of_total "$xoff" "$total_width")
elif [[ $xoff =~ ^- ]]; then
minus_xoff=${xoff#-}
xoff=$((total_width-minus_xoff))
fi
if [[ $yoff =~ %$ ]]; then
yoff=$(percent_of_total "$yoff" "$total_height")
elif [[ $yoff =~ ^- ]]; then
minus_yoff=${yoff#-}
yoff=$((total_height-minus_yoff))
fi
}
# meant to set non-local variables
split_geometry() { # <monitor geometry>
monitor_geo=$1
# x_begin=$(echo "$monitor_geo" | gawk -F '+' '{print $2}')
x_begin=${monitor_geo#*+}
x_begin=${x_begin%+*}
# y_begin=$(echo "$monitor_geo" | gawk -F '+' '{print $3}')
y_begin=${monitor_geo##*+}
# x_width=$(echo "$monitor_geo" | gawk -F 'x' '{print $1}')
x_width=${monitor_geo%x*}
# y_height=$(echo "$monitor_geo" | gawk -F 'x|+' '{print $2}')
y_height=${monitor_geo#*x}
y_height=${y_height%%+*}
}
update_geometry_settings_for_monitor() {
# 1. Correctly interpret width/height percentages when there exist multiple
# monitors so an initially created dropdown is the correct size (xdotool
# would create a dropdown the width of all screens for 100% width)
# 2. Force resize the dropdown to the correct percentage of the current
# monitor IF the monitor has changed since the last time the dropdown
# was used
# it is conceivable that a user may want to use -m but not -a, so
# get the wm from within this function
local current_monitor
if [[ $wm == bspwm ]]; then
current_monitor=$(bspc query --names --monitors --monitor)
elif [[ $wm == i3 ]]; then
# TODO use jq if installed
# I'd rather not make jq a dependency
current_monitor=$(i3-msg -t get_workspaces | sed 's/{"num"/\n/g' | \
gawk -F ',' '/focused":true/ {sub(".*output",""); gsub("[:\"]",""); print $1}')
fi
local monitor_geo x_begin y_begin x_width y_height
if [[ -n $current_monitor ]]; then
monitor_geo=$(xrandr --current | \
gawk "/^$current_monitor/ {gsub(\"primary \",\"\"); print \$3}")
split_geometry "$monitor_geo"
else
local current_x current_y monitors_info x_end y_end
if ! $pointer_monitor_detection; then
# determine current monitor using active window
local wid wininfo
wid=$(xdotool getactivewindow)
if [[ -z $wid ]]; then
# will try again after remapping or creating the dropdown
return 1
fi
wininfo=$(xwininfo -id "$wid")
current_x=$(echo "$wininfo" | gawk '/Absolute.*X/ {print $4}')
current_y=$(echo "$wininfo" | gawk '/Absolute.*Y/ {print $4}')
else
# shellcheck disable=SC2034
local X Y SCREEN WINDOW
# determine current monitor using pointer location
eval "$(xdotool getmouselocation --shell)"
current_x=X
current_y=Y
fi
monitors_info=$(xrandr --current | gawk '/ connected/ {gsub("primary ",""); print}')
while read -r monitor; do
monitor_geo=$(echo "$monitor" | gawk '{print $3}')
if [[ $monitor_geo =~ ^[0-9]+x[0-9]+\+[0-9]+\+[0-9]+$ ]]; then
split_geometry "$monitor_geo"
x_end=$((x_begin+x_width))
y_end=$((y_begin+y_height))
if [[ $current_x -ge $x_begin ]] && [[ $current_x -lt $x_end ]] && \
[[ $current_y -ge $y_begin ]] && [[ $current_y -lt $y_end ]]; then
# current_monitor=$(echo "$monitor" | gawk '{print $1}')
current_monitor=${monitor%% *}
break
fi
fi
done <<< "$monitors_info"
fi
# convert w/h/x/y percentages/negatives to pixels
convert_geometry_to_pixels "$x_width" "$y_height"
# update x and y offsets, so that will appear on correct screen
# (required for some WMs apparently, but not for others)
((xoff+=x_begin))
((yoff+=y_begin))
}
map_and_reset_geometry() {
xdotool windowmap "$wid" windowmove "$wid" "$xoff" "$yoff" \
windowsize "$wid" "$width" "$height" 2> /dev/null
}
# * WM Detection and Hooks
set_wm() {
if ! $user_set_wm && $auto_detect_wm; then
local id
id=$(xprop -root -notype _NET_SUPPORTING_WM_CHECK)
id=${id##* }
# xfwm4 and fvwm at least will give two names (hence piping into head)
wm=$(xprop -notype -id "$id" _NET_WM_NAME | head -n 1)
wm=${wm##* }
wm=${wm//\"/}
fi
}
decoration_settings() {
if [[ -z $subtract_when_same ]]; then
if $auto_detect_wm \
&& [[ $wm =~ ^(Mutter|GNOME Shell|bspwm|i3|GoomwW)$ ]]; then
subtract_when_same=false
else
subtract_when_same=true
fi
fi
if [[ -z $dec_fix ]] && $auto_detect_wm; then
# settings for stacking/floating wms where can't get right position
# easily from xwininfo; take borders into account
if [[ $wm == Blackbox ]]; then
dec_fix="1x22"
elif [[ $wm =~ ^(Mutter|GNOME Shell)$ ]]; then
dec_fix="-10x-8"
elif [[ $wm =~ ^(Mutter \(Muffin\))$ ]]; then
dec_fix="-9x-8"
fi
fi
}
set_class() {
if [[ -z $class ]]; then
if [[ $program =~ ^emacsclient ]]; then
class=emacs
elif [[ $program =~ ^google-chrome ]]; then
class=google-chrome
elif [[ $program == st ]]; then
class=st-256color
elif [[ $program == gnome-terminal ]]; then
class=Gnome-terminal
elif [[ $program =~ ^urxvt.* ]]; then
class=urxvt
elif [[ $program == xiatec ]]; then
class=xiate
elif [[ $program == alacritty ]]; then
class=Alacritty
elif [[ $program == current ]]; then
class=$(cat "$MUTDROP_PATH"/current"$num"_class 2> /dev/null)
else
class=$program
fi
fi
}
is_floating() {
if [[ -n $is_floating ]]; then
eval "$is_floating $1"
elif $auto_detect_wm; then
if [[ $wm == i3 ]]; then
# TODO make sure this returns 1 on failure
i3-msg -t get_tree | gawk 'gsub(/{"id"/, "\n{\"id\"")' | \
gawk '/focused":true.*floating":"user_on/ {print $1}'
elif [[ $wm == bspwm ]]; then
bspc query -T -n | grep '"state":"floating"'
else
return 0
fi
else
return 0
fi
}
pre_float() {
if [[ $wm == bspwm ]]; then
# newest (using "instance" names)
if [[ $class =~ [A-Z] ]]; then
bspc rule -a "$class" -o state=floating
else
bspc rule -a \*:"$class" -o state=floating
fi
fi
}
post_float() {
if [[ $wm == awesome ]]; then
echo 'local awful = require("awful") ; awful.client.floating.set(c, true)' | \
awesome-client
elif [[ $wm == i3 ]]; then
i3-msg "[id=$wid] floating enable" > /dev/null
elif [[ $wm == herbstluftwm ]]; then
herbstclient fullscreen on
fi
}
pre_create() {
if [[ -n $pre_create ]]; then
eval "$pre_create"
fi
}
post_create() {
if [[ -n $post_create ]]; then
eval "$post_create"
fi
}
pre_map() {
float=${1:-true}
if [[ $float != false ]]; then
if [[ -n $pre_float ]]; then
eval "$pre_float"
elif $auto_detect_wm; then
pre_float
fi
fi
if [[ -n $pre_map ]]; then
eval "$pre_map"
fi
}
map_and_post_map() {
# always reset geometry
map_and_reset_geometry
float=${1:-true}
if [[ $float != false ]]; then
if [[ -n $post_float ]]; then
eval "$post_float"
elif $auto_detect_wm; then
post_float
fi
fi
# need to set geometry again if wasn't previously floating
map_and_reset_geometry
if [[ -n $post_map ]]; then
eval "$post_map"
fi
}
pre_unmap() {
if [[ -n $pre_unmap ]]; then
eval "$pre_unmap"
fi
}
post_unmap() {
if [[ -n $post_unmap ]]; then
eval "$post_unmap"
fi
}
unmap() {
hide=$1
pre_unmap
xdotool windowunmap "$wid"
if [[ -z $hide ]]; then
if [[ $wm == herbstluftwm ]]; then
# TODO should only happen if wasn't previously fullscreen
herbstclient fullscreen off
fi
fi
post_unmap
}
# Old notes:
# floating WMs that may move a window after remapping it
# pekwm|Fluxbox|Blackbox|xfwm4|Metacity|FVWM|Sawfish|GoomwW|Mutter|GNOME Shell|Mutter \(Muffin\)|KWin|Metacity \(Marco\)|[Cc]ompiz|bspwm
# floating WMs that may both move and resize a window after remapping it
# Openbox
# * General Helper Functions
get_class_name() {
local class
class=$(xprop -id "$1" WM_CLASS 2> /dev/null)
class=${class##* }
class=${class//\"/}
echo "$class"
}
get_visibility() {
xwininfo -id "$1" 2> /dev/null | gawk '/Map State/ {print $3}'
}
maybe_cancel_auto_show() {
if $cancel_auto_show && \
[[ $1 == $(cat "$MUTDROP_PATH"/auto_hidden/wid 2> /dev/null) ]]; then
# shellcheck disable=SC2188
> "$MUTDROP_PATH"/auto_hidden/wid
fi
}
program_start() {
local program_command tmux_command wid
program_command=("$program")
if [[ $program == alacritty ]]; then
# prevent alacritty from resizing the terminal to 80x24
program_command+=(-d 0 0)
fi
program_command+=("${program_flags[@]}")
if [[ -n $session_name ]]; then
session_name=$(printf "%q" "$session_name")
tmux_command="tmux attach-session -dt $session_name || \
tmuxifier load-session $session_name || \
tmuxinator start $session_name || \
tmux new-session -s $session_name"
# note: st will work with or without the -e flag (like kitty)
# note: regular console works with or without quotes, but trinity's
# konsole only works without quotes
if [[ $program =~ ^(urxvt|alacritty|xiatec|st|lxterminal|qterminal|cool-retro-term|lilyterm|konsole$) ]]; then
program_command+=(-e bash -c "$tmux_command")
elif [[ $program == kitty ]]; then
program_command+=(bash -c "$tmux_command")
else
program_command+=(-e "\"bash -c $tmux_command\"")
fi
fi
wid=$(xtoolwait -wid "${program_command[@]}")
if [[ -n $name ]]; then
xdotool set_window --name "$name" "$wid"
fi
echo "$wid" > "$MUTDROP_PATH/$program$num"
echo -n "$wid"
}
current_create() {
# turns active window into a dropdown
local wid
wid=$(xdotool getactivewindow)
echo "$wid" > "$MUTDROP_PATH"/current"$num"
get_class_name "$wid" > "$MUTDROP_PATH"/current"$num"_class
if [[ -n $name ]]; then
xdotool set_window --name "$name" "$wid"
fi
echo -n "$wid"
}
wid_toggle() {
# used for -m option; at first tdrop assumes that there is a focused window
# on the current desktop; if there isn't (and the WM doesn't have some way
# to query the current monitor), this will be set to false, and tdrop will
# have to find out the current monitor info after opening the dropdown
# (currently, using xwininfo to find the position of a window is the only
# WM-independent way I know to find out what the current monitor is)
local focused_window_exists
focused_window_exists=true
# deal with percentages/negatives when no -m
if ! $monitor_aware; then
local total_geo total_width total_height
total_geo=$(xwininfo -root | gawk '/geometry/ {gsub("+*",""); print $2}')
# total_width=$(echo "$total_geo" | gawk -F 'x' '{print $1}')
total_width=${total_geo%x*}
# total_height=$(echo "$total_geo" | gawk -F 'x' '{print $2}')
total_height=${total_geo#*x}
convert_geometry_to_pixels "$total_width" "$total_height"
fi
# get saved window id if already created
local exists visibility
# cat to silence error
wid=$(cat "$MUTDROP_PATH/$program$num" 2> /dev/null)
exists=true
if [[ -n $wid ]]; then
visibility=$(get_visibility "$wid")
# sometimes xwininfo will still report a window as existing hence xprop check
if [[ -z $visibility ]] || ! xprop -id "$wid" &> /dev/null; then
# window no longer exists
exists=false
# shellcheck disable=SC2188
> "$MUTDROP_PATH/$program$num"
fi
else
exists=false
fi
if $exists; then
if [[ $visibility =~ ^(IsUnMapped|IsUnviewable)$ ]]; then
# visibility will be IsUnMapped on most WMs if the dropdown is open
# on another desktop; may also be IsUnviewable
xdotool set_desktop_for_window "$wid" "$(xdotool get_desktop)"
if [[ $(get_visibility "$wid") == IsUnMapped ]]; then
pre_map
else
xdotool windowactivate "$wid"
fi
# update here if possible so this doesn't cause a delay
# between the window being remapped and resized
if $monitor_aware; then
update_geometry_settings_for_monitor || \
focused_window_exists=false
fi
map_and_post_map
# cancel auto-show for a window when manually remapping it
maybe_cancel_auto_show "$wid"
if ! $focused_window_exists; then
# need to use dropdown as active window to get monitor info
update_geometry_settings_for_monitor
# always resize/move; if monitor hasn't changed then it won't be
# necessary, but it won't cause problems either
map_and_reset_geometry
fi
else
unmap
fi
else
# necessary to deal with negative width or height
# if creating on an empty desktop and can't determine the monitor,
# must set temporary values for negative width and/or height
local original_width original_height
if $monitor_aware && ! update_geometry_settings_for_monitor; then
focused_window_exists=false
if [[ $width =~ ^- ]]; then
original_width=$width
width=100%
fi
if [[ $height =~ ^- ]]; then
original_height=$height
height=100%
fi
fi
# make it
pre_create
if [[ $program == current ]]; then
wid=$(current_create)
unmap
else
pre_map
wid=$(program_start)
map_and_post_map
# update window dimensions if necessary
if ! $focused_window_exists; then
width=${original_width:-$width}
height=${original_height:-$height}
update_geometry_settings_for_monitor
map_and_reset_geometry
fi
fi
post_create
fi
}
# * Helper Functions for Auto Hiding/Showing
get_geometry() {
# so that won't float a tiled window later when showing
if is_floating "$1" &> /dev/null; then
local wininfo x y rel_x rel_y width height
wininfo=$(xwininfo -id "$1")
x=$(echo "$wininfo" | gawk '/Absolute.*X/ {print $4}')
y=$(echo "$wininfo" | gawk '/Absolute.*Y/ {print $4}')
rel_x=$(echo "$wininfo" | gawk '/Relative.*X/ {print $4}')
rel_y=$(echo "$wininfo" | gawk '/Relative.*Y/ {print $4}')
if [[ $subtract_when_same != false ]]; then
# behaviour works for most WMs (at least floating ones)
x=$((x-rel_x))
y=$((y-rel_y))
else
# don't subtract when abs and rel values are the same
# necessary for WMs like bspwm and i3
if [[ $x -ne $rel_x ]]; then
x=$((x-rel_x))
fi
if [[ $y -ne $rel_y ]]; then
y=$((y-rel_y))
fi
fi
width=$(xwininfo -id "$(xdotool getactivewindow)" | \
gawk '/Width/ {print $2}')
height=$(xwininfo -id "$(xdotool getactivewindow)" | \
gawk '/Height/ {print $2}')
echo -n -e "xoff=$x\nyoff=$y\nwidth=$width\nheight=$height"
else
# window is not floating; don't bother saving geometry
echo -n "false"
fi
}
# set global xoff, yoff, width, and height based on stored values
restore_geometry() {
local x_fix y_fix
eval "$(< "$MUTDROP_PATH"/auto_hidden/geometry)"
if [[ -n $dec_fix ]]; then
x_fix=$(echo "$dec_fix" | gawk -F "x" '{print $1}')
y_fix=$(echo "$dec_fix" | gawk -F "x" '{print $2}')
xoff=$((xoff-x_fix))
yoff=$((yoff-y_fix))
fi
}
toggle_auto_hide() {
local no_hide
no_hide=$(cat "$MUTDROP_PATH"/auto_hidden/no_hide 2> /dev/null)
mkdir -p "$MUTDROP_PATH"/auto_hidden
if [[ -z $no_hide ]]; then
echo "true" > "$MUTDROP_PATH"/auto_hidden/no_hide
else
# shellcheck disable=SC2188
> "$MUTDROP_PATH"/auto_hidden/no_hide
fi
}
# * Auto Hiding/Showing
auto_hide() {
local no_hide
no_hide=$(cat "$MUTDROP_PATH"/auto_hidden/no_hide 2> /dev/null)
if [[ -z $no_hide ]]; then
wid=$(xdotool getactivewindow)
mkdir -p "$MUTDROP_PATH"/auto_hidden
echo "$wid" > "$MUTDROP_PATH"/auto_hidden/wid
get_class_name "$wid" > "$MUTDROP_PATH"/auto_hidden/class
get_geometry "$wid" > "$MUTDROP_PATH"/auto_hidden/geometry
unmap hide
fi
}
auto_show() {
local no_hide
no_hide=$(cat "$MUTDROP_PATH"/auto_hidden/no_hide 2> /dev/null)
if [[ -z $no_hide ]]; then
local was_floating
wid=$(< "$MUTDROP_PATH"/auto_hidden/wid)
class=$(< "$MUTDROP_PATH"/auto_hidden/class)
was_floating=$(< "$MUTDROP_PATH"/auto_hidden/geometry)
restore_geometry "$wid"
pre_map "$was_floating"
map_and_post_map "$was_floating"
fi
}
# * Hide All
hide_all() {
shopt -s nullglob dotglob
local dropdowns
dropdowns=("$MUTDROP_PATH"/*)
for dropdown in "${dropdowns[@]}"; do
# cat to silence errors
wid=$(cat "$dropdown" 2> /dev/null)
unmap "$wid" 2> /dev/null
done
shopt -u nullglob dotglob
}
# * Main
# ** Setup
set_wm
decoration_settings
set_class
# ** Primary Action
if $clearwid; then
# shellcheck disable=SC2188
> "$MUTDROP_PATH/$program$num"
elif [[ $program == toggle_auto_hide ]]; then
toggle_auto_hide
elif [[ $program == auto_hide ]]; then
auto_hide
elif [[ $program == auto_show ]]; then
auto_show
elif [[ $program == hide_all ]]; then
hide_all
else
wid_toggle
fi
# vim is dumb
# vim: set ft=sh noet:

@ -1,201 +0,0 @@
.\" Man page for tdrop.
.\" Please make an issue on the online repository if you find errors or typos.
.TH TDROP 1 "11 February 2015" "tdrop 0.2" "tdrop man page"
.SH NAME
Tdrop - make dropdown terminals and windows
.SH SYNOPSIS
tdrop [\fIOPTIONS\fR] [program name or cmd] [program options ...]
.SH DESCRIPTION
Tdrop is used for hiding/unhiding programs to acheive quake/dropdown functionality. It can create a dropdown window if one does not already exist or turn the current window into a dropdown on the fly. It provides options to control the intial size and position of dropdowns, for example to leave panels visible or to deal with window borders. When used with a terminal, it provides an option to specify the name of a tmux session to automatically start. It also allows the user to specify arbitrary options/flags to be used when starting programs. It uses window IDs as opposed to classes, so it can be used with multiple windows of the same program.
It also has the ability to automatically hide and automatically show dropdowns. For example, it can be used to automatically hide a terminal when opening something from it, e.g. an image viewer, video player, etc. Tdrop can then automatically bring back the terminal whenever the image view, video player, etc. is closed. See the Examples section for more information.
.SH Commands
Tdrop expects the name of a program or 'current' (to use the current window) as the last argument to create a dropdown (optionally followed by any flags to that program). Alternatively, it can take one of auto_show, auto_hide, toggle_auto_hide, or hide_all. If hide_all is given instead of a program name, tdrop will hide all visible dropdowns.
Tdrop's functionality is not particularly useful called directly from the command line. Commands should either be bound to a key, used in shell functions/aliases, or used with a file opener (e.g. in the rifle.conf).
.SH OPTIONS
.br
E.g.
.br
$ tdrop -y 15 termite
.br
$ tdrop --y-offset=15 termite
.br
$ tdrop --y-offset 15 termite
.TP
Note that all hook and command related options can make use of any tdrop variables (such as $width, $height, $xoff, $yoff, $class, $wid, etc.). Note that for some of the hooks, the window id is not guarunteed to be known (since the window may not have yet been created), so any scripts that make use of these should check if it is defined (pre-map and pre-float; wid will never be known for pre-create).
.TP
\fB-w WIDTH\fR, \fB --width=WIDTH\fR
Specify a width for a created window as a number or percentage. A negative number is allowed (e.g. '-w -4') in which case the width will be that many pixels less than 100% of the screen size (or monitor size if '-m' is being used). This fixes the problem where 100% width may actually go over the screen due to window borders/decoration. The other other geometry options also accept negative values ('-h', '-x', and '-y'). (default: 100%)
.TP
\fB-h HEIGHT\fR, \fB --height=HEIGHT\fR
Specify a height for a created window as a number or percentage. (default: 45%)
.TP
\fB-x OFFSET\fR, \fB --x-offset=OFFSET\fR
Specify the x position for a created window as a number or percentage. (default: 0)
.TP
\fB-y OFFSET\fR, \fB --y-offset=OFFSET\fR
Specify the y position for a created window as a number or percentage. (default: 1, see BUGS)
.TP
\fB-s NAME\fR, \fB --session=NAME\fR
Specify a tmuxinator, tmuxifier, or tmux session name to start. An existing tmux session has highest precedence and will be connected to with '-d', detaching other attached clients. If a there is no tmuxinator/tmuxifier/etc. session of the given name, a normal tmux session with the name will be created. If this option is not given, tmux will not be used. Note that this option requires that the program be a supported terminal. (default: none)
.TP
\fB-n NUMBER\fR, \fB --number=NUMBER\fR
Specify a number (or any extra text) to differentiate between dropdowns of the same program (this is only needed when using multiple dropdowns of the same program). This flag can also be used for creating multiple different dropdowns on the fly ('current'). Note that it is not necessary to use this to deal with multi-user systems as tdrop stores dropdown information separately for each user. (default: none)
.TP
\fB-c COMMAND\fR, \fB --pre-create-hook=COMMAND\fR
Specify a command to execute before first creating or initializing a dropdown (before mapping a normal dropdown or before unmapping the 'current' window). This flag has no effect for the auto_(hide|show) commands. (default: none)
.TP
\fB-C\fR, \fB --post-create-hook=COMMAND\fR
Specify a command to execute after first creating or initializing a dropdown (after mapping a normal dropdown or after unmapping the 'current' window). This flag has no effect for the auto_(hide|show) commands. (default: none)
.TP
\fB-p COMMAND\fR, \fB --pre-map-hook=COMMAND\fR
Specify a command to execute before showing/mapping a dropdown. Note that this will run when showing a dropdown for the first time even when --pre-create-hook is used. (default: none)
.TP
\fB-P COMMAND\fR, \fB --post-map-hook=COMMAND\fR
Specify a command to execute after showing/mapping a dropdown. Note that this will run when hiding a dropdown for the first time even when --post-create-hook is used. (default: none)
.TP
\fB-u COMMAND\fR, \fB --pre-unmap-hook=COMMAND\fR
Specify a command to execute before hiding/unmapping a dropdown. (default: none)
.TP
\fB-U COMMAND\fR, \fB --post-unmap-hook=COMMAND\fR
Specify a command to execute after hiding/unmapping a dropdown. (default: none)
.TP
\fB-l COMMAND\fR, \fB --pre-map-float-command=COMMAND\fR
Specify a command execute before showing/mapping a dropdown in order to float the dropdown (e.g. a bspwm oneshot rule). This may be useful if you don't want to float all windows of a given program and tdrop doesn't automatically support this for your window manager with the -a flag. This will override any default floating command when used with -a.
.TP
\fB-L COMMAND\fR, \fB --post-map-float-command=COMMAND\fR
Specify a command execute after showing/mapping a dropdown in order to float the dropdown. This may be useful if you don't want to float all windows of a given program and tdrop doesn't automatically support this for your window manager with the -a flag. This can be used if your window manager does not support floating rules at all; for example, it can be used to fake a key combination (e.g. using xdotool) that will float the current window. This will override any default floating command when used with -a.
.TP
\fB-d DEC_SIZE\fR, \fB --decoration-fix=DEC_SIZE\fR
Specify a window decoration/border size in the form <x decoration size>x<y decoration size> to be taken into account when saving window position. This should not be necessary for most window managers and is only used with 'auto_show', e.g. 'tdrop -d 1x22 auto_show' for blackbox. (default: none)
.TP
\fB-S\fR, \fB --no-subtract-when-same\fR
This option is a more complicated companion to -d that is also unlikely to be needed. This is used to determine how to calculate the X and Y position of a window using xwininfo when 'auto_hide' is used (if the absolute and relative X or Y values are reported as the same, this option determines the behavior). If you are sure you have the decoration size correct, but windows are still being restored in an incorrect position with 'auto_show', you may want to try using this. Takes no argument. (default: false)
.TP
\fB-i\fR, \fB --is-floating\fR
Specify a command that will determine whether the current window is floating ($wid can be used in the command instead). Only used for the auto_hide command. This will be used to save whether the current window is floating or not. When restoring the window, if there is a float command and the window was previously floating, it will be floated. (default: none)
.TP
\fB-f\fR, \fB --program-flags\fR
NOTE: Using this flag is deprecated; it may be removed in the future. Instead, specify program flags after the program (e.g. "tdrop kitty --name foo").
Specify flags/options that the terminal or program should be called with. For example, to set the title of the terminal, something like 'tdrop -f "--title mytitle" <program>' can be used.
Caution: If there is a tmux session specified (with -s), the option to execute a program (usually -e for terminal programs) is implicitly added by tdrop! (default: none)
.TP
\fB-a\fR, \fB --auto-detect-wm\fR
If there are available settings for the detected window manager for the -l, -L, -d, and/or -i options, automatically set them. Takes no argument. Manually specified settings take precedence. This can be used both for dropdowns and the auto_(hide|show) commands. Takes no argument. (default: false)
.TP
\fB-m\fR, \fB --monitor-aware\fR
This option only applies for dropdowns (not auto-hiding and auto-showing). Specify that geometry values should be relative to the current monitor. For example, if the width is a percentage or negative value, the pixel width will be calculated as a percentage of the current monitor's width (instead of the combined width of all monitors). If the monitor changes, this option will cause a dropdown to be resized to fit the given percentages. Note that this option assumes xrandr is being used and requires xrandr to work. (default: false)
.TP
\fB-t\fR, \fB --pointer-monitor-detection\fR
Use mouse pointer location for detecting which monitor is the current one so terminal will be displayed on it. Without this option, the monitor with currently active window is considered the current one. This option is only effective if -m / --monitor-aware option is enabled.
.TP
\fB --wm=NAME\fR
Specify the window manager name (which determines the default settings when -a is specified). This may be useful if you've change the name of your window manager using wmname as this will prevent tdrop from correctly detecting the real window manager name. This could also potentially be useful if the all the default -a settings for another window manager work with the current one (e.g. if using a similar but differently named fork of some window manager). (default: automatically detected)
.TP
\fB --class=NAME\fR
Providing this option lets tdrop know what the class (or classname) of the window is (it does not actually set the class for a window). This is used for window managers like bspwm that use the class for floating rules. For some commonly used programs, tdrop will already use the correct class. This option is useful when the program name and class are not the same and there is not already a default mapping between the two. (default: the program name or a known substitution)
Both the class and classname of a window can be obtained using xprop (see WM_CLASS). As for the difference, generally the class starts with an uppercase letter and the classname starts with a lowercase letter. The xprop output may only list one for some programs (e.g. urxvt only has "urxvt"). Currently this option is only useful for bspwm, and it does not matter whether the class or classname (which bspwm calls an instance name) is provided, so the user does not really need to worry about the distinction.
.TP
\fB --name=NAME\fR
This option only applies for dropdowns (not auto-hiding and auto-showing). Set a new name for the dropdown window (see _NET_WM_NAME and WM_NAME in xprop output). This option may be useful if you want to add specific rules just for dropdowns with a program like compton by giving them a common title. (default: none)
.TP
\fB --clear\fR
Used to clear a saved window id for the given program or 'current' instead of creating a dropdown. Takes no argument.
.TP
\fB --no-cancel\fR
Specifies that manually re-showing an auto-hidden window with tdrop should not cancel an auto_show. Takes no argument. See the examples.
\fB --timeout\fR
Specifies the timeout in to wait for a window to appear when starting a program before giving up. This prevents a tdrop process from sticking around forever if a program fails to start. (default: 10)
.TP
\fB --help\fR
Print basic help information. Takes no argument.
.SH EXAMPLES
.SS Making Dropdowns
Use a key binding program such as sxhkd to bind keys to these commands.
The simplest example to make a dropdown for an xterm:
.br
$ tdrop xterm
When using a tiling window manager like bspwm, dropdowns like guake will by default be tiled instead of floated. One can create a rule to float every instance of guake or another dropdown. However, one may not want to float every instance of a terminal used with tdrop. Tdrop allows the user to run their own commands at various points during execution, for example before mapping the window:
.br
$ tdrop -p "bspc rule -a xterm -o floating=on" xterm
Tdrop also provides tested settings for certain window managers. One can use the '-a' flag if settings exist for the current window manager. For example, if bspwm is the window manager, the following command is the same as the above command and will work for whatever terminal/program is specified and will also work with 'tdrop auto_show'. For a list of window managers with tested settings see the readme or the script itself.
.br
$ tdrop -a xterm
Tdrop supports controlling the initial size and placement of a terminal. The border of a window may need to be taken into an account. For example, I use a border size of 2, so I use 4 less than my screen size. I also use a y-offset of 14 so that the dropdown doesn't hide my panel:
.br
$ tdrop -a -w 1362 -y 14 xterm
Tdrop can also create a tmux session if it does not exist:
.br
$ tdrop -a -w 1362 -y 14 -s dropdown xterm
Tdrop allows for having multiple dropdowns of the same type:
.br
$ tdrop xterm
.br
$ tdrop -n 1 xterm
.br
$ tdrop -n 2 xterm
.br
...
Tdrop works with normal windows (with some potential visual annoyance, see BUGS):
.br
$ tdrop zathura
.br
# the current window
.br
$ tdrop current
Once a window is turned into a dropdown, the key bound to 'tdrop ... current' will continue to toggle that window until it is closed. Then the key can be used to create a new dropdown. '-n' can also be used to have multiple 'current' keys. If an active window is accidentally turned into a dropdown, it can be cleared:
.br
$ tdrop --clear current
.br
# clear a specific number
.br
$ tdrop -n 1 --clear current
.SS Auto-hiding/showing
These example will work even for non-dropdown terminals.
Tdrop provides the functionality to get programs/terminals out of the way when opening other programs. For example, when opening an image viewer from a normal floating dropdown, the dropdown will be over the image viewer. This requires an extra hotkey press to hide the dropdown. If one wants to return to the dropdown after looking at images, the hotkey must be once again invoked. Tdrop allows for this process to be automated.
For example, this could be added to a shell's config/startup file:
.br
hide_on_open() { tdrop -a auto_hide; "$@" && tdrop -a auto_show }
To use it in an alias when writing a commit message in an graphical $EDITOR started from a terminal:
.br
alias gc='hide_on_open git commit'
This will hide the terminal window when opening the commit editor and then reshow the terminal once the editor is closed. It should also maintain the window's position and size when showing it. If the window moves down and to the right every time it is auto-hidden and then shown again, the user may need to specify a -d value. Alternatively, if one already exists for the user's window manager, -a can be used to automatically set it. The -l and -L options are also used with auto_show and can be set automatically with -a if default settings exist for the current window manager.
Note that for tiling window managers that support 'tdrop -a auto_show', reshowing a window will always float the window (even if it was orignally tiled) if -i is not specified. To prevent this, also use 'tdrop -a auto_hide' if your window manager is supported. Otherwise, -i must be manually specified with auto_hide.
This functionality might lead to some unwanted "re-shows" of dropdown. Consider a situation in which one opens an image viewer from a dropdown and leaves it open for a while, resuming normal use of the dropdown. When the image viewer is closed, the dropdown appears, unwanted. Tdrop is smart about this and won't "re-show" a dropdown if it has been manually toggled since an auto-hide. If you don't want this check to happen, use '--no-cancel' in your dropdown key binding.
Auto-hiding functionality is particularly nice to use with a file opener like rifle:
.br
mime ^image, has sxiv, X, flag f = tdrop auto_hide ; sxiv -a -- "$@" && tdrop -a auto_show
.SH BUGS
If -y is set to 0, a window may be subsequently moved to the middle when showing/mapping it with xdotool. This may have to do with the window border.
.SH AUTHOR
Fox Kiester <noct at posteo\&.net>
.br
Source: https://github.com/noctuid/tdrop
.SH SEE ALSO
xdotool(1), sxhkd(1), xprop(1), xwininfo(1), tmux(1)
Loading…
Cancel
Save