1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
#!/bin/sh
# Move windows according to my workflow. Check bin/gnome-set-config to
# see its key-binding.
#
# GNOME on Wayland does not expose native windows to wmctrl. Prefer the
# Workspace Router GNOME Shell extension, which runs inside Shell and can
# see both Wayland and Xwayland windows. Fall back to wmctrl for sessions
# where the extension is unavailable.
workspace_router_call() {
method="$1"
command -v gdbus >/dev/null 2>&1 || return 1
gdbus call \
--session \
--dest name.rbenencia.WorkspaceRouter \
--object-path /name/rbenencia/WorkspaceRouter \
--method "name.rbenencia.WorkspaceRouter.$method"
}
is_x11_session() {
[ "${XDG_SESSION_TYPE:-}" = "x11" ] || {
[ -n "${DISPLAY:-}" ] && [ -z "${WAYLAND_DISPLAY:-}" ]
}
}
is_wayland_session() {
[ "${XDG_SESSION_TYPE:-}" = "wayland" ] || [ -n "${WAYLAND_DISPLAY:-}" ]
}
print_diagnostics() {
if workspace_router_call ListWindows >/tmp/gnome-move-windows-router.out 2>/tmp/gnome-move-windows-router.err; then
router_status="available"
router_preview=$(sed -n '1p' /tmp/gnome-move-windows-router.out)
else
router_status="unavailable"
router_preview=$(sed -n '1p' /tmp/gnome-move-windows-router.err)
fi
if command -v wmctrl >/dev/null 2>&1; then
wmctrl_count=$(wmctrl -l 2>/dev/null | wc -l | awk '{print $1}')
else
wmctrl_count="not-installed"
fi
echo "session_type=${XDG_SESSION_TYPE:-unknown}"
echo "display=${DISPLAY:-unset}"
echo "wayland_display=${WAYLAND_DISPLAY:-unset}"
echo "workspace_router=${router_status}"
echo "workspace_router_preview=${router_preview:-none}"
echo "wmctrl_window_count=${wmctrl_count}"
if is_wayland_session && [ "$router_status" != "available" ]; then
echo "diagnosis=Wayland session without Workspace Router; fallback can only manage Xwayland windows"
fi
}
warn_wayland_fallback() {
echo "gnome-move-windows: Workspace Router is unavailable on Wayland; falling back to wmctrl, which only sees some windows" >&2
echo "gnome-move-windows: Run 'gnome-move-windows --diagnose' and ensure the workspace-router-cli GNOME extension is enabled" >&2
}
case "$1" in
--list)
workspace_router_call ListWindows
exit $?
;;
--diagnose)
print_diagnostics
exit $?
;;
esac
if [ -z "$GNOME_MOVE_WINDOWS_FORCE_WMCTRL" ] && ! is_x11_session; then
if workspace_router_call RouteWindows >/dev/null 2>&1; then
exit 0
fi
if is_wayland_session; then
warn_wayland_fallback
fi
fi
command -v wmctrl >/dev/null 2>&1 || {
echo "gnome-move-windows: Workspace Router is unavailable and wmctrl is not installed" >&2
exit 1
}
# Move all windows to the primary display. If they're on the secondary
# display, and we try to move them to a workspace, it won't work.
move_windows_to_primary() {
window_ids=$(wmctrl -l | awk '{print $1}')
maximized_windows=""
fullscreen_windows=""
has_xprop=0
command -v xprop >/dev/null 2>&1 && has_xprop=1
for window_id in $window_ids; do
if [ "$has_xprop" -eq 1 ]; then
state=$(xprop -id "$window_id" _NET_WM_STATE 2>/dev/null || true)
case "$state" in
*"_NET_WM_STATE_MAXIMIZED_VERT"*"_NET_WM_STATE_MAXIMIZED_HORZ"*|*"_NET_WM_STATE_MAXIMIZED_HORZ"*"_NET_WM_STATE_MAXIMIZED_VERT"*)
maximized_windows="$maximized_windows $window_id"
;;
esac
case "$state" in
*"_NET_WM_STATE_FULLSCREEN"*)
fullscreen_windows="$fullscreen_windows $window_id"
;;
esac
fi
wmctrl -i -r "$window_id" -b remove,fullscreen
wmctrl -i -r "$window_id" -b remove,maximized_vert,maximized_horz
done
sleep 0.2
for window_id in $window_ids; do
wmctrl -i -r "$window_id" -e 0,0,0,-1,-1
done
sleep 0.2
for window_id in $maximized_windows; do
wmctrl -i -r "$window_id" -b add,maximized_vert,maximized_horz
done
for window_id in $fullscreen_windows; do
wmctrl -i -r "$window_id" -b add,fullscreen
done
}
move_windows_to_primary
# Assign windows to predetermined workplaces
misc=$(wmctrl -xl | awk 'tolower($0) ~ /(com\\.cisco\\.secureclient|secure client|anyconnect|vpnui|keepass)/ {print $1}')
main="$(wmctrl -xl | awk 'tolower($0) ~ / emacs/ {print $1}')"
communications="$(wmctrl -xl | awk 'tolower($0) ~ /(webex|slack|communications|notmuch|outlook|elfeed|thunderbird)/ {print $1}')"
media="$(wmctrl -xl | awk 'tolower($0) ~ /(youtube|spotify)/ {print $1}')"
terminals="$(wmctrl -xl | awk 'tolower($0) ~ /(alacritty|kitty|terminal)/ {print $1}')"
teleport="$(wmctrl -xl | awk 'tolower($0) ~ /teleport/ {print $1}')"
browsers="$(wmctrl -xl | awk 'tolower($0) ~ /(firefox|chrom)/ {print $1}')"
for window_id in $misc; do
wmctrl -i -r "$window_id" -t 4
done
for window_id in $main; do
wmctrl -i -r "$window_id" -t 0
done
for window_id in $browsers; do
wmctrl -i -r "$window_id" -t 1
done
for window_id in $communications; do
wmctrl -i -r "$window_id" -t 2
done
for window_id in $terminals; do
wmctrl -i -r "$window_id" -t 3
done
for window_id in $teleport; do
wmctrl -i -r "$window_id" -t 5
done
for window_id in $media; do
wmctrl -i -r "$window_id" -t 8
done
|