Difference between revisions of "Custom Window Snap"
(→Gosnap Script) |
(→Gosnap Script) |
||
| Line 120: | Line 120: | ||
get_window_state | get_window_state | ||
| − | while getopts ": | + | while getopts ":LlRrMmNndih" opt;do |
case $opt in | case $opt in | ||
L) | L) | ||
| Line 168: | Line 168: | ||
print_info | print_info | ||
;; | ;; | ||
| − | + | h) | |
| + | usage | ||
| + | exit | ||
| + | ;; | ||
| + | *) | ||
echo "Invalid option: -$OPTARG" >&2 | echo "Invalid option: -$OPTARG" >&2 | ||
usage | usage | ||
| Line 308: | Line 312: | ||
# No window shadow: add this line to /etc/environment then relog | # No window shadow: add this line to /etc/environment then relog | ||
# MUFFIN_NO_SHADOWS=1 | # MUFFIN_NO_SHADOWS=1 | ||
| − | # | + | #</source> |
| − | </source> | ||
Latest revision as of 22:39, 31 July 2020
Many desktop environments for Linux have had window snapping (a.k.a window tiling or edge snapping) for a long time. It is a feature that I use very heavily, especially with hotkeys. I have been very dissatisfied with the way Linux desktop environments have handled this. They almost work the way I want, but not quite. I decided to take control of this.
Gosnap stands for "Good Old Snap" and replaces the window snapping/tiling feature on just about any Linux distro that uses the X Window System.
Download
| Filename | Description | Size | Modified | Link |
|---|---|---|---|---|
|
gosnap |
The Gosnap bash script. | 6.4K | 7/31/2020 |
Installing
wget https://beardedmaker.com/wiki/files/gosnap
chmod a+x gosnap
sudo mv gosnap /usr/binUsage
Usage: gosnap [-L | -l | -R | -r | -M | -m | -N | -n | -d | -i]
-L snap left
-l snap left dynamically
-R snap right
-r snap right dynamically
-M maximize window
-m toggle maximize window
-N minimize window
-n minimize window dynamically
-d resize to default geometry (current default: 0,10,60,826,556)
-i print window informationIf your desktop environment supports custom hotkeys, you can simply map any hotkey you want to execute this script with the appropriate parameter. For example:
- Snap Left:
gosnap -lSuper+Left - Snap Right:
gosnap -rSuper+Right - Snap Maximize:
gosnap -mSuper+Up - Snap Minimize:
gosnap -lSuper+Down
Note: To "snap dynamically" means to go to a "default" position as an intermediate step depending on the window's current position. For example, if I minimize the window using gosnap -n, but the window was previously maximized, I'd rather the window pop into the middle of the screen on the first invocation, and then when I minimize again I want the window to collapse to the taskbar. To just immediately minimize the window, use gosnap -N instead.
Gosnap Script
1 #!/bin/bash
2 #
3 # GOSNAP: Good Old Snap
4 #
5 # Script to emulate the Aero Snap feature in Windows 7
6 # Use -L or -R flags to snap left or right
7 # Use -l or -r flags to snap dynamically (intermediate default position)
8 # Use -M flag to maximize
9 # Use -m flag to toggle maximized state
10 # Use -N flag to minimize
11 # Use -n flag to minimize dynamically (intermediate default position)
12 # Use -d flag to reset the window state to default
13 # Use -i flag to print window info to stdout
14 #
15 # wmctrl -e g,x,y,w,h (any value set to -1 won't be changed)
16 # g = window gravity (just set to 0)
17 # x = window x position
18 # y = window y position
19 # w = window width
20 # h = window height
21 #
22
23 # CONFIGURATION
24 # =============
25
26 # Default window geometry to use with -d
27 # Format: gravity, x_pos, y_pos, width, height)
28 window_default="0,10,60,826,556"
29
30 # The x position reported by xdotool when the window is snapped left/right.
31 # For some reason, snapping the window to 0,0 does not actually register as 0,0.
32 # Use the -i flag while the terminal window is snapped to the left or the right
33 # to get the values unique to your screen.
34 left_origin_x=10
35 right_origin_x=692
36
37 # Add this to the half screen width value for snapping left/right.
38 # If you see gaps on the left or right wien you snap, you may need to adjust this.
39 half_width_adjust_left=1
40 half_width_adjust_right=1
41
42 # Adjust these to avoid issues with gaps
43 snap_left_x=0
44 snap_left_y=0
45 snap_right_x=0
46 snap_right_y=1
47
48 # Use wmctrl bug avoidance
49 # For some reason, wmctrl intermittently snaps to the wrong position.
50 # Doing "snap_default && snap_maximize" before snapping left/right seems to fix it.
51 # The trade-off using this fix is that snapping left/right has a very slight delay.
52 wmctrl_bug_fix=true
53
54 function main
55 {
56 check_args $@
57 check_command wmctrl
58 check_command xdotool
59 get_window_state
60
61 while getopts ":LlRrMmNndih" opt;do
62 case $opt in
63 L)
64 snap_left
65 ;;
66 l)
67 if $window_snapped_right;then
68 snap_default
69 else
70 snap_left
71 fi
72 ;;
73 R)
74 snap_right
75 ;;
76 r)
77 if $window_snapped_left;then
78 snap_default
79 else
80 snap_right
81 fi
82 ;;
83 M)
84 snap_maximize
85 ;;
86 m)
87 if $window_maximized;then
88 snap_default
89 else
90 snap_maximize
91 fi
92 ;;
93 N)
94 snap_minimize
95 ;;
96 n)
97 if $window_maximized || $window_snapped_left || $window_snapped_right;then
98 snap_default
99 else
100 snap_minimize
101 fi
102 ;;
103 d)
104 snap_default
105 ;;
106 i)
107 print_info
108 ;;
109 h)
110 usage
111 exit
112 ;;
113 *)
114 echo "Invalid option: -$OPTARG" >&2
115 usage
116 exit 1
117 ;;
118 esac
119 done
120 }
121
122 function check_args
123 {
124 if [[ "$@" == "" ]];then
125 usage
126 fi
127 }
128
129 function usage
130 {
131 echo
132 echo "Usage: gosnap [-L | -l | -R | -r | -M | -m | -N | -n | -d | -i]"
133 echo " -L snap left"
134 echo " -l snap left dynamically"
135 echo " -R snap right"
136 echo " -r snap right dynamically"
137 echo " -M maximize window"
138 echo " -m toggle maximize window"
139 echo " -N minimize window"
140 echo " -n minimize window dynamically"
141 echo " -d resize to default geometry (current default: $window_default)"
142 echo " -i print window information"
143 echo
144 }
145
146 function check_command
147 {
148 if [[ ! -e $(which $1) ]];then
149 echo -e "\nERROR: $1 was not found on your system!\n"
150 # If we're on Ubuntu, use the c-n-f functionality
151 if [[ -x /usr/lib/command-not-found ]];then
152 python /usr/lib/command-not-found -- $1
153 elif [[ -x /usr/share/command-not-found ]];then
154 python /usr/share/command-not-found -- $1
155 fi
156 usage
157 exit 1
158 fi
159 }
160
161 function get_window_state
162 {
163 screen_width=$(xdpyinfo | grep 'dimensions:' | cut -f 2 -d ':' | cut -f 1 -d 'x' | xargs)
164 window_id=$(xdotool getactivewindow)
165 window_id_hex=$(printf 0x%x $window_id)
166 window_properties=$(xprop -id $window_id)
167 window_state=$(echo $window_properties | grep "_NET_WM_STATE(ATOM)")
168 window_geometry=$(xdotool getwindowgeometry $window_id)
169 window_pos_x=$(echo $window_geometry | awk '{print $4}' | awk -F, '{print $1}')
170 window_pos_y=$(echo $window_geometry | awk '{print $4}' | awk -F, '{print $2}')
171 window_width=$(echo $window_geometry | awk '{print $8}' | awk -Fx '{print $1}')
172 window_height=$(echo $window_geometry | awk '{print $8}' | awk -Fx '{print $2}')
173 window_max_horiz=false
174 if [ $(echo $window_state | grep -o "_NET_WM_STATE_MAXIMIZED_HORZ") ];then
175 window_max_horiz=true
176 fi
177 window_max_vert=false
178 if [ $(echo $window_state | grep -o "_NET_WM_STATE_MAXIMIZED_VERT") ];then
179 window_max_vert=true
180 fi
181 window_maximized=false
182 if $window_max_horiz && $window_max_vert;then
183 window_maximized=true
184 fi
185 window_snapped_left=false
186 if $window_max_vert && [ $window_pos_x == $left_origin_x ];then
187 window_snapped_left=true
188 fi
189 window_snapped_right=false
190 if $window_max_vert && [ $window_pos_x == $right_origin_x ];then
191 window_snapped_right=true
192 fi
193 }
194
195 function snap_maximize
196 {
197 wmctrl -r :ACTIVE: -b add,maximized_vert,maximized_horz
198 }
199
200 function snap_minimize
201 {
202 xdotool getactivewindow windowminimize
203 }
204
205 function snap_default
206 {
207 wmctrl -r :ACTIVE: -b remove,maximized_vert,maximized_horz
208 wmctrl -r :ACTIVE: -e $window_default
209 }
210
211 function snap_left
212 {
213 if $wmctrl_bug_fix; then snap_default && snap_maximize;fi
214 halfw=$((($screen_width/2)+$half_width_adjust_left))
215 wmctrl -r :ACTIVE: -b remove,maximized_vert,maximized_horz &&\
216 wmctrl -r :ACTIVE: -b add,maximized_vert &&\
217 wmctrl -r :ACTIVE: -e 0,$snap_left_x,$snap_left_y,$halfw,-1
218 }
219
220 function snap_right
221 {
222 if $wmctrl_bug_fix; then snap_default && snap_maximize;fi
223 halfw=$((($screen_width/2)+$half_width_adjust_right+$snap_right_x))
224 wmctrl -r :ACTIVE: -b remove,maximized_vert,maximized_horz &&\
225 wmctrl -r :ACTIVE: -b add,maximized_vert &&\
226 wmctrl -r :ACTIVE: -e 0,$halfw,$snap_right_y,$halfw,-1
227 }
228
229 function print_info
230 {
231 echo "screen_width = $screen_width (half = $(($screen_width/2)))"
232 echo "Window $window_id ($window_id_hex)"
233 echo "$(echo $window_geometry | tr -d '\n' | grep -o 'Position.*' | xargs)"
234 echo "window_max_horiz = $window_max_horiz"
235 echo "window_max_vert = $window_max_vert"
236 echo "window_maximized = $window_maximized"
237 echo "window_snapped_left = $window_snapped_left"
238 echo "window_snapped_right = $window_snapped_right"
239 exit
240 }
241
242 main $@
243
244 # OTHER NOTES
245 #
246 # xdotool windowmove $(xdotool getactivewindow) 0 0
247 # xdotool windowmove $(xdotool getactivewindow) 100% 100%
248 # xdotool windowsize $(xdotool getactivewindow) 50% 100%
249 # xdotool getwindowgeometry $(xdotool getactivewindow)
250 #
251 # No window shadow: add this line to /etc/environment then relog
252 # MUFFIN_NO_SHADOWS=1
253 #