diff --git a/README.md b/README.md index 599cf22..63e8555 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,10 @@ alt + s ``` ### Basic Flags -`-s` should only be used for terminals if the user wants to start a tmux or tmuxinator session. `-W` should be used if the program to start is not a terminal with an `-e` flag. `-a` should be used to set up WM specific rules (which are required for the --width, --height, --xoff, and --yoff flags to work properly; see below for supported WMs). Long options require using `--opt=` as opposed to leaving a space. Refer to `tdrop --help` and the manpage for more complete instructions. +`-s` should only be used for supported terminals and if the user wants to start a tmux or tmuxinator session. `-a` should be used to set up WM specific rules (which are required for the --width, --height, --xoff, and --yoff flags to work properly; see below for supported WMs). Long options require using `--opt=` as opposed to leaving a space. Refer to `tdrop --help` and the manpage for more complete instructions. + +*Changes* +Old users please note that `-W|--normal-window`, `-z|--sleep-terminal`, and `-Z|--sleep-window` are no longer necessary and have been removed. ### Flicker For some window managers that require a window to be repositioned after re-mapping it, some flicker may be noticeable. With a recent change, this flicker is pretty much gone for some window managers (e.g. in the Gnome Shell and Cinnamon DEs) and slightly better than before in other @@ -67,7 +70,7 @@ mime ^video, has mpv, X, flag f = tdrop -a auto_hide && mpv -- "$@" && tdrop -a ## Tested With ### Terminals - Termite -- URxvt +- URxvt (including urxvtd) - XTerm - Xfce4-terminal - Gnome-terminal @@ -75,7 +78,7 @@ mime ^video, has mpv, X, flag f = tdrop -a auto_hide && mpv -- "$@" && tdrop -a - Terminology - Sakura - Roxterm -- Terminix +- Terminix (-s will not work if the terminix process is already running) If your terminal doesn't work with tdrop, feel free to make an issue. diff --git a/tdrop b/tdrop index 4827d68..b481c74 100755 --- a/tdrop +++ b/tdrop @@ -14,19 +14,16 @@ options: -w width specify a width for a newly created term (default: 45%) -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 BUGS in man) - -s name name for tmux or tmuxinator session (if not given, will not use tmux) + -s name name for tmux or tmuxinator session (requires the program to be a supported terminal) -n num num or extra text; only needed if want multiple dropdowns of same program (default: "") -p cmd provide a pre-map command to float the window if necessary -P cmd provide a post-map command to float the window if necessary -M cmd provide a post-unmap command; can be used for example with a window manager that doesn't support floating to turn fullscreen on when mapping a terminal then off when unmapping it -O cmd provide a one time command only for when a dropdown is created/initiated (useful for 'tdrop current') -d XxY give decoration/border size to accurately save position; only applicable with auto_show; on applicable with a few window managers (e.g. blackbox) - -z use a different sleep time to wait for terminal to be created (advanced; see man page) - -Z use a different sleep time for -W program to be created (advanced; see man page) -f specify flags/options to be used when creating the term or window (e.g. -f '--title mytitle', default: none) -a automatically detect window manager and if settings exist for it, automatically set -p, -P, and -d values as necessary; this can have affect when used with a terminal or with auto_show or auto_hide (default: false) -m for use with multiple monitors and only with dropdowns (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 reszing of the dropdown when the monitor changes (default: false) - -W the given program is not a terminal (or lacks an -e flag) (default: assume it IS a terminal) --clear clear saved window id; useful 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 term after it is auto-hidden) @@ -57,18 +54,12 @@ map_post="" unmap_post="" oneshot_post="" dec_fix="" -sleep_term_time=0.01 -sleep_term_user_set=false -sleep_win_time=0.5 -sleep_win_user_set=false program_flags="" -normal_window=false clearwid=false cancel_auto_show=true -term=${*:0-1} auto_detect_wm=false monitor_aware=false -while getopts :h:w:x:y:s:n:p:P:M:O:d:z:Z:f:-:Wam opt +while getopts :h:w:x:y:s:n:p:P:M:O:d:f:-:am opt do case $opt in h) height=$OPTARG;; @@ -82,12 +73,7 @@ do M) unmap_post=$OPTARG;; O) oneshot_post=$OPTARG;; d) dec_fix=$OPTARG;; - z) sleep_term_time=$OPTARG - sleep_term_user_set=true;; - Z) sleep_win_time=$OPTARG - sleep_win_user_set=true;; f) program_flags=$OPTARG;; - W) normal_window=true;; a) auto_detect_wm=true;; m) monitor_aware=true;; -) @@ -105,12 +91,7 @@ do post-unmap) unmap_post=$OPTARG;; oneshot-post) oneshot_post=$OPTARG;; decoration-fix) dec_fix=$OPTARG;; - sleep-terminal) sleep_term_time=$OPTARG - sleep_term_user_set=true;; - sleep-window) sleep_win_time=$OPTARG - sleep_win_user_set=true;; program-flags) program_flags=$OPTARG;; - normal-window) normal_window=true;; auto-detect-wm) auto_detect_wm=true;; monitor-aware) monitor_aware=true;; clear) clearwid=true;; @@ -260,14 +241,7 @@ wm_autoset_for_all() { elif [[ $wm == awesome ]]; then # awesome remembers size, but need to float and then set size first map_post_oneshot() { - # need sleep time to wait for window be created or will float wrong one.. - # not sure if there is a way to float by window id - if ! $sleep_win_user_set; then - # what I've had best results with - sleep_win_time=0.1 - fi - sleep $sleep_win_time && \ - echo 'local awful = require("awful") ; awful.client.floating.set(c, true)' | \ + echo 'local awful = require("awful") ; awful.client.floating.set(c, true)' | \ awesome-client && \ xdotool windowmove "$1" "$xoff" "$yoff" \ windowsize "$1" "$width" "$height" @@ -279,27 +253,15 @@ wm_autoset_for_all() { # tilers that won't remember sizing elif [[ $wm == i3 ]]; then - # need to sleep first time to wait for window to be created map_post_oneshot() { - if ! $sleep_win_user_set; then - # what I've had best results with - sleep_win_time=0.1 - fi - sleep $sleep_win_time && \ i3-msg "[id=$1] floating enable" > /dev/null && \ - xdotool windowmove "$1" "$xoff" "$yoff" \ - windowsize "$1" "$width" "$height" + xdotool windowmove "$1" "$xoff" "$yoff" \ + windowsize "$1" "$width" "$height" } map_post() { i3-msg "[id=$1] floating enable" > /dev/null && \ xdotool windowmove "$1" "$xoff" "$yoff" } - - # floating WMs that need extra sleep time to wait for dropdown to spawn initially - elif [[ $wm =~ ^(Fluxbox|Mutter|GNOME Shell|Mutter \(Muffin\)|KWin)$ ]]; then - if ! $sleep_term_user_set; then - sleep_term_time=0.05 - fi fi } @@ -397,8 +359,10 @@ map_pre_command() { # use automatically set function if exists elif [[ -n $(type map_pre 2> /dev/null) ]]; then # needed when creating oneshot rules for programs where cmd differs from actual class name - if [[ $1 == "gnome-terminal" ]]; then + if [[ $1 == gnome-terminal ]]; then map_pre "Gnome-terminal" + elif [[ $1 == urxvtc ]]; then + map_pre "urxvt" else map_pre "$1" fi @@ -437,57 +401,67 @@ maybe_cancel_auto_show() { # Dropdown Initialization # -term_create() { - local term_command="$term $program_flags" - if [[ $term == terminix ]]; then - sleep_term_time=0.3 +create_win_return_wid() { + local blacklist program_command pid visible_wid wids program_wid + # blacklist all existing wids of program + # (for programs where one pid shares all wids) + blacklist=$(xdotool search --classname "$program") + # need to redirect stdout or function won't return + program_command="$1 > /dev/null &" + # for programs where $! won't give the correct pid + if [[ $program == terminix ]] && pgrep terminix; then + pid=$(pgrep terminix) + eval "$program_command" + elif [[ $program == urxvtc ]]; then + blacklist=$(xdotool search --classname urxvtd) + pid=$(pgrep urxvtd) + eval "$program_command" + else + eval "$program_command" + pid=$! fi - if [[ -n $session_name ]]; then - # ugly workarounds due to how different terms' different -e flags work - if [[ $term == urxvt ]]; then - $term_command -e bash -c "sleep $sleep_term_time && xdotool getactivewindow > /tmp/tdrop/$term$num && xdotool getactivewindow windowmove $xoff $yoff windowsize $width $height && tmux attach-session -dt $session_name || tmuxinator start $session_name || tmux new-session -s $session_name" & - elif [[ $term == terminix ]]; then - $term_command -x "bash -c 'sleep $sleep_term_time && xdotool getactivewindow > /tmp/tdrop/$term$num && xdotool getactivewindow windowmove $xoff $yoff windowsize $width $height && tmux attach-session -dt $session_name || tmuxinator start $session_name || tmux new-session -s $session_name'" & - else - # starting with '/bin/bash -c' because required by termite - $term_command -e "/bin/bash -c 'sleep $sleep_term_time && xdotool getactivewindow > /tmp/tdrop/$term$num && xdotool getactivewindow windowmove $xoff $yoff windowsize $width $height && tmux attach-session -dt $session_name || tmuxinator start $session_name || tmux new-session -s $session_name'" & + visible_wid=false + while : ; do + wids=$(xdotool search --pid "$pid") + if [[ -n "$wids" ]]; then + while read -r wid; do + if [[ ! $blacklist =~ (^|$'\n')"$wid"($|$'\n') ]] && \ + [[ $(get_visibility "$wid") == IsViewable ]]; then + visible_wid=true + program_wid=$wid + fi + done <<< "$wids" fi - else - # not using hold, because flag is different for different terminals - if [[ $term == urxvt ]]; then - $term_command -e bash -c "sleep $sleep_term_time && xdotool getactivewindow > /tmp/tdrop/$term$num && xdotool getactivewindow windowmove $xoff $yoff windowsize $width $height && $SHELL" & - elif [[ $term == terminix ]]; then - $term_command -x "bash -c 'sleep $sleep_term_time && xdotool getactivewindow > /tmp/tdrop/$term$num && xdotool getactivewindow windowmove $xoff $yoff windowsize $width $height && $SHELL'" & - else - # not using hold, because flag is different for different terminals - $term_command -e "/bin/bash -c 'sleep $sleep_term_time && xdotool getactivewindow > /tmp/tdrop/$term$num && xdotool getactivewindow windowmove $xoff $yoff windowsize $width $height && $SHELL'" & + if $visible_wid; then + break fi - fi + sleep 0.01 + done + echo -n "$program_wid" } -win_create() { - local win_command="$term $program_flags" - $win_command & - # need to wait for window to be created - sleep $sleep_win_time - # often pids have two wids - local wid wid1 wid2 - wids=$(xdotool search --pid $!) - wid1=$(echo "$wids" | head -n 1) - wid2=$(echo "$wids" | tail -n 1) - if [[ -n $wid2 ]]; then - if [[ $(get_visibility "$wid2") == IsUnMapped ]]; then - wid=$wid1 +program_start() { + local program_command tmux_command wid + program_command="$program $program_flags" + if [[ -n "$session_name" ]]; then + tmux_command="'tmux attach-session -dt $session_name || \ + tmuxinator start $session_name || \ + tmux new-session -s $session_name'" + if [[ $program == urxvt ]]; then + program_command="$program_command -e bash -c $tmux_command" + elif [[ $program == terminix ]]; then + program_command="$program_command -x \"bash -c $tmux_command\"" else - wid=$wid2 + program_command="$program_command -e \"bash -c $tmux_command\"" fi - else - wid=$wid1 fi - # only works with pre-command + program_command="$program_command" + wid=$(create_win_return_wid "$program_command") + echo "$wid" > /tmp/tdrop/"$program$num" + # only will work if a pre-command has been run (e.g. bspwm) xdotool windowmove "$wid" "$xoff" "$yoff" \ windowsize "$wid" "$width" "$height" - echo "$wid" > /tmp/tdrop/"$term$num" + echo -n "$wid" } current_create() { @@ -503,7 +477,7 @@ wid_toggle() { mkdir -p /tmp/tdrop # get saved window id if already created local wid exists visibility - wid=$(< /tmp/tdrop/"$term$num") + wid=$(< /tmp/tdrop/"$program$num") exists=true if [[ -n $wid ]]; then visibility=$(get_visibility "$wid") @@ -511,17 +485,17 @@ wid_toggle() { if [[ -z $visibility ]] || [[ -z $(xprop -id "$wid") ]]; then # window no longer exists exists=false - > /tmp/tdrop/"$term$num" + > /tmp/tdrop/"$program$num" fi else exists=false fi if $exists; then if [[ $visibility == IsUnMapped ]]; then - if [[ $term == current ]]; then + if [[ $program == current ]]; then map_pre_command "$(< /tmp/tdrop/current"$num"_type)" else - map_pre_command "$term" + map_pre_command "$program" fi # update here if possible so this doesn't cause a delay # between the window being remapped and resized @@ -568,26 +542,12 @@ wid_toggle() { fi fi # make it - map_pre_command "$term" - local wid - if [[ $term == current ]]; then + map_pre_command "$program" + if [[ $program == current ]]; then wid=$(current_create) xdotool windowunmap "$wid" else - if $normal_window; then - win_create - else - term_create - fi - # get saved wid of newly created dropdown - wid="" - local count - count=0 - while [[ -z $wid ]] && [[ $count -lt 100 ]]; do - wid=$(< /tmp/tdrop/"$term$num") - sleep 0.01 - ((count++)) - done + wid=$(program_start) map_post_command oneshot "$wid" # update window dimensions if necessary if ! $focused_window_exists; then @@ -720,24 +680,24 @@ auto_show() { # Main # -if $auto_detect_wm; then - wm=$(get_window_manager) - wm_autoset_for_all - if [[ $term == auto_show ]] || [[ $term == auto_hide ]]; then - wm_autoset_for_hide_show - else - wm_autoset_for_dropdown - fi -fi - if [[ -n $1 ]]; then + program=${*:0-1} + if $auto_detect_wm; then + wm=$(get_window_manager) + wm_autoset_for_all + if [[ $program == auto_show ]] || [[ $program == auto_hide ]]; then + wm_autoset_for_hide_show + else + wm_autoset_for_dropdown + fi + fi if $clearwid; then - > /tmp/tdrop/"$term$num" - elif [[ $term == toggle_auto_hide ]]; then + > /tmp/tdrop/"$program$num" + elif [[ $program == toggle_auto_hide ]]; then toggle_auto_hide - elif [[ $term == auto_hide ]]; then + elif [[ $program == auto_hide ]]; then auto_hide - elif [[ $term == auto_show ]]; then + elif [[ $program == auto_show ]]; then auto_show else wid_toggle diff --git a/tdrop.groff b/tdrop.groff index 604782b..58af215 100644 --- a/tdrop.groff +++ b/tdrop.groff @@ -31,7 +31,7 @@ Specify the x position for a created window as a number or percentage. (default: Specify the y position for a created window as a number or percentage. (default: 1, see BUGS) .TP \fB\-s\fR, \fB \-\-session\fR -Specify a tmuxinator 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 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. (default: none) +Specify a tmuxinator 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 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\fR, \fB \-\-number\fR Specify a number to add when saving dropdown information. Only needed if multiple dropdowns of the same program are wanted. Can also be used for creating multiple different dropdowns on the fly. (default: none) @@ -51,18 +51,9 @@ Specify a post command to execute only when first creating or initiating a dropd \fB\-d\fR, \fB \-\-decoration-fix\fR Specify a window decoration/border size in the form x 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\-z\fR, \fB \-\-sleep-terminal\fR -Specify an alternate sleep time to wait for a terminal emulator to be completed. Only use this option if tdrop ends up capturing a different window as the dropdown when you press a dropdown key. You probably won't need to change this, and if you do, please report it. I hope to remove the need for sleeping entirely in the future. (default: 0.1) -.TP -\fB\-Z\fR, \fB \-\-sleep-window\fR -Specify an alternate sleep time to wait for a window to be completed. This is for use with -W or for -a with tiling window managers that cannot pre-float the next instance of a window (e.g. awesome and i3 if no rule to always float a specific class). Only use this option if tdrop ends up capturing a different window as the dropdown when you press a dropdown key. You probably won't need to change this, and if you do, please report it. I hope to remove the need for sleeping entirely in the future. (default: 0.5) -.TP \fB\-f\fR, \fB \-\-program-flags\fR Specify flags/options that the terminal or program should be called with. For example, to set the title of the terminal, something like '-f "--title mytitle"' can be used. (default: none) .TP -\fB\-W\fR, \fB \-\-normal-window\fR -Specifies that the program is not a terminal or does not have the '-e' flag; takes no argument. If using 'tdrop current', this option will have no effect either way. (default: false) -.TP \fB\-a\fR, \fB \-\-auto-detect-wm\fR If there are available settings for the detected window manager for the -p, -P, -M, and/or -d options, automatically set them; takes no argument. User set settings will still override these. This can be used with 'tdrop ', 'tdrop auto_hide', and 'tdrop auto_show'. For 'auto_hide', if the window manager is supported, it will check if the current window is tiled so that it is not changed to floating when auto-showing. (default: false) .TP @@ -147,9 +138,7 @@ mime ^image, has sxiv, X, flag f = tdrop auto_hide ; sxiv -a -- "$@" && tdrop -a .SH SEE ALSO xdotool(1), sxhkd(1), xprop(1), xwininfo(1), tmux(1) .SH BUGS -With terminals, it is easy to use the -e flag to reliably get window id and perform actions such as resizing. When using tdrop with a normal window (-W), the window id is gotten from the program's pid. This can be problematic when the pid has multiple window ids and the first one is not the desired one (I have yet to encounter this problem). More importantly, this means that tdrop has to wait to get the window id, resulting in a delay before it is floated/resized. This may cause visual annoyance when first creating a dropdown. There is a fork of xtoolwait that starts a program and returns its window id when created, but this has not been merged. Note that this only matters if the user wants to resize/float a normal window; it won't cause problems with a tiled dropdown. - -Also, 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. +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 Lit Wakefield .br