Skip to content

Instantly share code, notes, and snippets.

@tyjak
Last active March 12, 2025 11:42
Show Gist options
  • Save tyjak/f51b33d10d4e10edc89dde70f7597d6e to your computer and use it in GitHub Desktop.
Save tyjak/f51b33d10d4e10edc89dde70f7597d6e to your computer and use it in GitHub Desktop.
window
#!/bin/sh
#set -e
#set -u
#set -o pipefail
export LC_ALL=C
POPUP_DEFAULT_WIDTH=800
POPUP_DEFAULT_HEIGHT=600
# TODO refacto
# TODO try to simplify with delete class option and use only title, see howto do for default i3 class or in i3 keep only class and delete title in popup window i.e. vimwiki
# TODO add notification option ?
# FIXME -f option has high CPU usage...
# TODO get the user env => try to fix in i3pystatus to path the data
POPUP_TOP_POSITION=23
if [ -n "$HIDPI_SCALE" ]
then
POPUP_TOP_POSITION=$(printf "%.0f" $(echo "$POPUP_TOP_POSITION*$HIDPI_SCALE" | bc))
fi
# popup
# wrapper to create popup window in i3w
# dependancies: i3w, bc
# to set default predefined size, add this in your i3 config file for default window parameters :
# set $wfM_height 600
# set $wfM_width 1000
# for_window [class="_popup-notitle-medium-sticky"] border 1pixel, floating enable, resize set $wfM_width $wfL_height, move position center, sticky enable
# for_window [class="_popup-notitle-medium"] border 1pixel, floating enable, resize set $wfM_width $wfL_height, move position center
# for_window [class="_popup-notitle-sticky"] border 1pixel, floating enable, move position center, sticky enable
# for_window [class="_popup-notitle"] border 1pixel, floating enable, move position center
get_width ()
{
if [ -z "$width"] && [ -n "$windowsize" ]
then
width=${windowsize:1}
width=${width/x*/}
fi
echo ${width:-$POPUP_DEFAULT_WIDTH}
}
get_height ()
{
if [ -z "$height"] && [ -n "$windowsize" ]
then
height=${windowsize/*x/}
fi
echo ${height:-$POPUP_DEFAULT_HEIGHT}
}
# compute i3 resize
get_size () {
case "$windowsize" in
-small|-medium|-large) size="" ;;
*) size=", resize set ${width}px ${height}px" ;;
esac
echo $size
}
# compute i3 position
get_position () {
screen_size=$(xrandr --current | grep " connected" | cut -d" " -f4 | rev | cut -c 5- | rev)
screen_width=${screen_size/x*/}
screen_height=${screen_size/*x/}
pos=(${position//,/ }) # center, or [right|left],[top|bottom], or [0-9]+x[0-9]+
# TODO add env var for ypos (i3bar height) or process with font size get from i3 conf
xpos=0
ypos=$POPUP_TOP_POSITION
# TODO default width and height by env var ? or get from i3 var conf ?
# TODO add condition if borderless or not and add 2 pixel only if a border is defined
move_x="center"
for p in "${pos[@]}"
do
case "$p" in
right) move_x=$(printf "%.0f px " $(echo "${screen_width}-${width:-802}" | bc));; # +2px because default popup with border 1px
left) move_x="$xpos px ";;
top) move_y="$ypos px";;
bottom) move_y=$(printf "%.0f px" $(echo "${screen_height}-${height:-602}" | bc));; # +2px because default popup with border 1px
center) move=center;;
[0-9]*x[0-9]*) position_raw=$p;;
esac
done
if [ -n "$move" ]
then
echo ", move position $move "
elif [ -n "$position_raw" ]
then
echo ", move position ${position_raw/*x/} px ${position_raw/x*/} px "
else
echo ", move position ${move_x}${move_y} "
fi
}
debug () {
if [ -n "${debug}" ]
then
echo "class: $class"
echo "bin: $bin"
if [ -n "$position" ]
then
screen_size=$(xrandr --current | grep " connected" | cut -d" " -f4 | rev | cut -c 5- | rev)
screen_width=${screen_size/*x/}
screen_height=${screen_size/x*/}
pos=(${position//,/ })
echo "width: $(get_width) / height: $(get_height)"
echo "screen_size: ${screen_size}"
echo "screen_width: ${screen_width} / screen_height: ${screen_height}"
echo "move_x: ${move_x} / move_y: ${move_y}"
fi
fi
}
usage() {
printf >&2 "Usage: $0 [-t (window title)] [-c (window class)] [-s medium] [-p center|[0-9]+x[0-9]+|(left|right)|(top|bottom)] [-S] [-f] [-o (shell option)] (-e) command
-t title
-c class
-s small|medium|large|HxW
-p [center|[0-9]+x[0-9]+|[left|right],[top|bottom]]
-S : sticky
-f : keep cmd in foreground
-o : shell option
-h hide
-e : command (-e optional and deprecated)
-d : debug mode"
}
while getopts "t:c:s:p:H:W:Sfo:e:hd" o
do case "$o" in
t) options="--title $OPTARG"
title=${OPTARG};;
c) class="${OPTARG}";;
s) windowsize="-${OPTARG}";;
p) position="${OPTARG}";;
H) height=${OPTARG};; #deprecated
W) width=${OPTARG};; #deprecated
S) windowsticky="-sticky";;
f) foreground=' --hold';;
o) shell_option=" -o ${OPTARG}";;
e) bin=${OPTARG};;
h) hide=1;;
d) debug=1;;
*)
usage
exit 1;;
esac
done
shift "$(($OPTIND -1))"
if [ -z "$*" ] && [ -z "${bin}" ]
then
usage
exit 1;
else
bin=${*:-${bin}}
fi
bin_cleaned=${bin%% *}
title=${title:-${bin_cleaned}}
is_running=$( ps -eo cmd | grep -c "^${TERMINAL} --title ${title:-${bin_cleaned}}" )
class="${class:-_popup-notitle}${windowsize}${windowsticky}${foreground}"
#TODO try to simplify popup run test
#is_running=$(pgrep $bin_cleaned | wc -l)
exec_i3="exec \"${TERMINAL} --title ${title:-${bin_cleaned}} --class ${class} ${shell_option} -o cursor.style=Underline -e ${bin}\""
if [ -n "${debug}" ]
then
echo "bin cleaned: $bin_cleaned"
echo "is running: $is_running ($( ps -eo cmd | grep "${TERMINAL} --title ${title}}"))"
echo "pgrep $bin_cleaned: $(pgrep $bin_cleaned | wc -l)"
echo "title: ${title}"
echo "bin: ${bin}${foreground}"
echo "i3-msg: i3-msg -t command \"${exec_i3}\""
fi
if [ ${is_running} -eq 0 ]
then
width=$(get_width)
height=$(get_height)
if [ -n "${HIDPI_SCALE}" ]
then
[ -n "${debug}" ] && echo "HIDPI scale" ${HIDPI_SCALE}
if [ -n "${height}" ] && [ -n "${width}" ]
then
height=$(printf "%.0f" $(echo "${height}*${HIDPI_SCALE}" | bc))
width=$(printf "%.0f" $(echo "${width}*${HIDPI_SCALE}" | bc))
[ -n "${debug}" ] && echo "SIZE: ${width} ${height}"
fi
fi
geo=$(get_size)$(get_position)
[ -n "${debug}" ] && echo "geo: $geo"
[ -n "${windowsticky}" ] && sticky=', sticky enable'
i3-msg -t command "${exec_i3}"
if [ -n "$hide" ]
then
scratchpad='[title="'${title}'"] border 1pixel, floating enable, move scratchpad, scratchpad show '${geo}${sticky}
[ -n "${debug}" ] && echo "scratchpad: $scratchpad"
#while ! i3-msg -t get_tree | grep -qs "\"class\":\"${class#*,}\""
while ! i3-msg -t get_tree | grep -qs "\"title\":\"${title}\""
do
[ -n "${debug}" ] && echo "waiting.."
done
i3-msg -t command "$scratchpad"
elif [ -n "${geo}" ]
then
while ! i3-msg -t get_tree | grep -qs "\"title\":\"${title}\""
do
[ -n "${debug}" ] && echo "${exec_i3}"
[ -n "${debug}" ] && echo "${title}"
[ -n "${debug}" ] && echo "waiting.."
done
i3-msg -t command '[title="'${title:-${bin_cleaned}}'" floating] '${geo}${sticky}
fi
elif [ -n "${hide}" ]
then
show='[title="'${title:-${bin_cleaned}}'" floating] scratchpad show'
[ -n "${debug}" ] && echo "show: $show"
i3-msg -t command "$show"
else
[ -n "${debug}" ] && echo "kill"
i3-msg -t command '[title="'${title:-${bin_cleaned}}'" floating] kill'
fi
# GistID: f51b33d10d4e10edc89dde70f7597d6e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment