#!/bin/bash #todo: # cancel for tile function # determine what windows are maximized and re-max after the "window select" function # determine what windows are non-resizable by the user so that the script doesn't resize them # cascade also shaded windows # winfuncsh select # winfuncs tile # winfuncs tiletwo # winfuncs tiletwol # winfuncs tiletwor # winfuncs tilethree # winfuncs tilethreev # winfuncs stacktwo # winfuncs cascade # winfuncs showdesktop # set gaps (0 removes gaps) outer_gaps=2 inner_gaps=2 # set gaps for 'select' mode expose_gaps=20 # set desktop dimensions display_width=$(xdotool getdisplaygeometry | cut -d" " -f1) display_height=$(xdotool getdisplaygeometry | cut -d" " -f2) # desktop height without panel(s) desktop_height=$(xprop -root _NET_WORKAREA | awk '{ print $6 }' | cut -d"," -f1) # window decorations window_id=$(xdotool getactivewindow) titlebar_offset=$(xwininfo -id "$window_id" | awk '/Relative upper-left Y:/ { print $4 }') # top panel top_bar=$(xprop -root _NET_WORKAREA | awk '{ print $4 }' | cut -d"," -f1) # bottom panel (not needed) bottom_bar=`expr $display_height - $desktop_height - $top_bar` function get_desktop_dim { if (( ${#DIM[@]} == 0 )) ; then DIM=(`expr $display_width - $outer_gaps \* 2` `expr $desktop_height - $outer_gaps \* 2`) fi } # which workspace we're on function get_workspace { if [[ "$DTOP" == "" ]] ; then DTOP=`xdotool get_desktop` fi } function is_desktop { xwininfo -id "$*" | grep '"Desktop"' return "$?" } function get_visible_window_ids { if (( ${#WDOWS[@]} == 0 )) ; then WDOWS=(`xdotool search --desktop $DTOP --onlyvisible "" 2>/dev/null`) fi } function win_showdesktop { get_workspace get_visible_window_ids command="search --desktop $DTOP \"\"" if (( ${#WDOWS[@]} > 0 )) ; then command="$command windowminimize %@" else command="$command windowraise %@" fi echo "$command" | xdotool - } function win_tile_two { get_desktop_dim wid1=`xdotool selectwindow 2>/dev/null` is_desktop "$wid1" && return wid2=`xdotool selectwindow 2>/dev/null` is_desktop "$wid2" && return half_w=`expr ${DIM[0]} / 2` win_h=${DIM[1]} commands="windowsize $wid1 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowsize $wid2 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowmove $wid1 $outer_gaps `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid2 `expr $half_w + $outer_gaps + $inner_gaps` `expr $top_bar + $outer_gaps`" commands="$commands windowraise $wid1" commands="$commands windowraise $wid2" wmctrl -i -r $wid1 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid2 -b remove,maximized_vert,maximized_horz echo "$commands" | xdotool - } function win_tile_two_left { get_desktop_dim wid1=`xdotool selectwindow 2>/dev/null` is_desktop "$wid1" && return wid2=`xdotool selectwindow 2>/dev/null` is_desktop "$wid2" && return half_w=`expr ${DIM[0]} / 3` win_h=${DIM[1]} commands="windowsize $wid1 `expr $half_w \* 2 - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowsize $wid2 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowmove $wid1 $outer_gaps `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid2 `expr $half_w \* 2 + $outer_gaps + $inner_gaps` `expr $top_bar + $outer_gaps`" commands="$commands windowraise $wid1" commands="$commands windowraise $wid2" wmctrl -i -r $wid1 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid2 -b remove,maximized_vert,maximized_horz echo "$commands" | xdotool - } function win_tile_two_right { get_desktop_dim wid1=`xdotool selectwindow 2>/dev/null` is_desktop "$wid1" && return wid2=`xdotool selectwindow 2>/dev/null` is_desktop "$wid2" && return half_w=`expr ${DIM[0]} / 3` win_h=${DIM[1]} commands="windowsize $wid1 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowsize $wid2 `expr $half_w \* 2 - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowmove $wid1 $outer_gaps `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid2 `expr $half_w + $outer_gaps + $inner_gaps` `expr $top_bar + $outer_gaps`" commands="$commands windowraise $wid1" commands="$commands windowraise $wid2" wmctrl -i -r $wid1 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid2 -b remove,maximized_vert,maximized_horz echo "$commands" | xdotool - } function win_stack_two { get_desktop_dim wid1=`xdotool selectwindow 2>/dev/null` is_desktop "$wid1" && return wid2=`xdotool selectwindow 2>/dev/null` is_desktop "$wid2" && return win_w=${DIM[0]} half_h=`expr ${DIM[1]} / 2` commands="windowsize $wid1 `expr $win_w` `expr $half_h - $titlebar_offset - $inner_gaps`" commands="$commands windowsize $wid2 `expr $win_w` `expr $half_h - $titlebar_offset - $inner_gaps`" commands="$commands windowmove $wid1 $outer_gaps `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid2 $outer_gaps `expr $half_h + $top_bar + $outer_gaps + $inner_gaps`" commands="$commands windowraise $wid1" commands="$commands windowraise $wid2" wmctrl -i -r $wid1 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid2 -b remove,maximized_vert,maximized_horz echo "$commands" | xdotool - } function win_tile_three { get_desktop_dim wid1=`xdotool selectwindow 2>/dev/null` is_desktop "$wid1" && return wid2=`xdotool selectwindow 2>/dev/null` is_desktop "$wid2" && return wid3=`xdotool selectwindow 2>/dev/null` is_desktop "$wid3" && return win_h=${DIM[1]} half_w=`expr ${DIM[0]} / 2` half_h=`expr ${win_h} / 2` commands="windowsize $wid1 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowsize $wid2 `expr $half_w - $inner_gaps` `expr $half_h - $titlebar_offset - $inner_gaps`" commands="$commands windowsize $wid3 `expr $half_w - $inner_gaps` `expr $half_h - $titlebar_offset - $inner_gaps`" commands="$commands windowmove $wid1 $outer_gaps `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid2 `expr $half_w + $outer_gaps + $inner_gaps` `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid3 `expr $half_w + $outer_gaps + $inner_gaps` `expr $half_h + $top_bar + $outer_gaps + $inner_gaps`" commands="$commands windowraise $wid1" commands="$commands windowraise $wid2" commands="$commands windowraise $wid3" wmctrl -i -r $wid1 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid2 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid3 -b remove,maximized_vert,maximized_horz echo "$commands" | xdotool - } function win_tile_three_v { get_desktop_dim wid1=`xdotool selectwindow 2>/dev/null` is_desktop "$wid1" && return wid2=`xdotool selectwindow 2>/dev/null` is_desktop "$wid2" && return wid3=`xdotool selectwindow 2>/dev/null` is_desktop "$wid3" && return win_h=${DIM[1]} half_w=`expr ${DIM[0]} / 3` commands="windowsize $wid1 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowsize $wid2 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowsize $wid3 `expr $half_w - $inner_gaps` `expr $win_h - $titlebar_offset`" commands="$commands windowmove $wid1 $outer_gaps `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid2 `expr $half_w + $outer_gaps + $inner_gaps / 2` `expr $top_bar + $outer_gaps`" commands="$commands windowmove $wid3 `expr $half_w \* 2 + $outer_gaps + $inner_gaps` `expr $top_bar + $outer_gaps`" commands="$commands windowraise $wid1" commands="$commands windowraise $wid2" commands="$commands windowraise $wid3" wmctrl -i -r $wid1 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid2 -b remove,maximized_vert,maximized_horz wmctrl -i -r $wid3 -b remove,maximized_vert,maximized_horz echo "$commands" | xdotool - } function win_tile { get_workspace get_visible_window_ids (( ${#WDOWS[@]} < 1 )) && return; get_desktop_dim # determine how many rows and columns we need cols=`echo "sqrt(${#WDOWS[@]})" | bc` rows=$cols wins=`expr $rows \* $cols` if (( "$wins" < "${#WDOWS[@]}" )) ; then cols=`expr $cols + 1` wins=`expr $rows \* $cols` if (( "$wins" < "${#WDOWS[@]}" )) ; then rows=`expr $rows + 1` wins=`expr $rows \* $cols` fi fi (( $cols < 1 )) && cols=1; (( $rows < 1 )) && rows=1; win_w=`expr ${DIM[0]} / $cols` win_h=`expr ${DIM[1]} / $rows` # do tiling x=0; y=0; commands="" for window in ${WDOWS[@]} ; do wmctrl -i -r $window -b remove,maximized_vert,maximized_horz commands="$commands windowsize $window `expr $win_w - $inner_gaps \* 2` `expr $win_h - $titlebar_offset - $inner_gaps \* 2`" commands="$commands windowmove $window `expr $x \* $win_w + $outer_gaps` `expr $y \* $win_h + $top_bar + $outer_gaps`" x=`expr $x + 1` if (( $x > `expr $cols - 1` )) ; then x=0 y=`expr $y + 1` fi done echo "$commands" | xdotool - } function expose { get_workspace get_visible_window_ids (( ${#WDOWS[@]} < 1 )) && return; get_desktop_dim # determine how many rows and columns we need cols=`echo "sqrt(${#WDOWS[@]})" | bc` rows=$cols wins=`expr $rows \* $cols` if (( "$wins" < "${#WDOWS[@]}" )) ; then cols=`expr $cols + 1` wins=`expr $rows \* $cols` if (( "$wins" < "${#WDOWS[@]}" )) ; then rows=`expr $rows + 1` wins=`expr $rows \* $cols` fi fi (( $cols < 1 )) && cols=1; (( $rows < 1 )) && rows=1; win_w=`expr ${DIM[0]} / $cols` win_h=`expr ${DIM[1]} / $rows` # do tiling x=0; y=0; commands="" for window in ${WDOWS[@]} ; do wmctrl -i -r $window -b remove,maximized_vert,maximized_horz commands="$commands windowsize $window `expr $win_w - $expose_gaps \* 2` `expr $win_h - $titlebar_offset - $expose_gaps \* 2`" commands="$commands windowmove $window `expr $x \* $win_w + $expose_gaps` `expr $y \* $win_h + $top_bar + $expose_gaps`" x=`expr $x + 1` if (( $x > `expr $cols - 1` )) ; then x=0 y=`expr $y + 1` fi done echo "$commands" | xdotool - } function win_cascade { get_workspace get_visible_window_ids (( ${#WDOWS[@]} < 1 )) && return; x=0; y=0; commands="" for window in ${WDOWS[@]} ; do wmctrl -i -r $window -b remove,maximized_vert,maximized_horz commands="$commands windowsize $window 1024 640" commands="$commands windowmove $window `expr $x + $outer_gaps` `expr $y + $top_bar + $outer_gaps`" x=`expr $x + 100` y=`expr $y + 80` done echo "$commands" | xdotool - } function win_select { get_workspace get_visible_window_ids (( ${#WDOWS[@]} < 1 )) && return; # store window positions and widths i=0 for window in ${WDOWS[@]} ; do GEO=`xdotool getwindowgeometry $window | grep Geometry | sed 's/.* \([0-9].*\)/\1/g'`; height[$i]=`echo $GEO | sed 's/\(.*\)x.*/\1/g'` width[$i]=`echo $GEO | sed 's/.*x\(.*\)/\1/g'` # ( xwininfo gives position not ignoring titlebars and borders, unlike xdotool ) POS=(`xwininfo -stats -id $window | grep 'geometry ' | sed 's/.*[-+]\([0-9]*[-+][0-9*]\)/\1/g' | sed 's/[+-]/ /g'`) posx[$i]=${POS[0]} posy[$i]=${POS[1]} i=`expr $i + 1` done # tile windows expose # select a window wid=`xdotool selectwindow 2>/dev/null` is_desktop "$wid" && return # restore window positions and widths i=0; commands="" for (( i=0; $i<${#WDOWS[@]}; i++ )) ; do commands="$commands windowsize ${WDOWS[i]} ${height[$i]} ${width[$i]}" commands="$commands windowmove ${WDOWS[i]} ${posx[$i]} ${posy[$i]}" done commands="$commands windowraise $wid" echo "$commands" | xdotool - } for command in ${@} ; do if [[ "$command" == "tile" ]] ; then win_tile elif [[ "$command" == "select" ]] ; then win_select elif [[ "$command" == "tiletwo" ]] ; then win_tile_two elif [[ "$command" == "tiletwol" ]] ; then win_tile_two_left elif [[ "$command" == "tiletwor" ]] ; then win_tile_two_right elif [[ "$command" == "stacktwo" ]] ; then win_stack_two elif [[ "$command" == "tilethree" ]] ; then win_tile_three elif [[ "$command" == "tilethreev" ]] ; then win_tile_three_v elif [[ "$command" == "cascade" ]] ; then win_cascade elif [[ "$command" == "showdesktop" ]] ; then win_showdesktop fi done