我正在尝试编写一个脚本来识别所有打开的 chrome 窗口并将它们移动到大屏幕上的网格布局中
我不知道如何找出最佳分辨率,所以我要手动将它们添加到一个数组中,如果有 1 个 chrome 窗口可用,则最大化它,如果有 2 个 chrome 窗口可用,则转到一个数组来查找该窗口的大小?
目前,我可以移动屏幕上的每个窗口(这样做会破坏我的显示屏)但我能看到如何只移动 chrome 屏幕?
下面的脚本是我的一些想法,但请指出正确的方向,因为目前脚本不起作用
#!/bin/bash
#Chrome window crontroller
# Monitor 1920 X 1800
# Choose array for number of screens available
# Different screen positions
G=0
win1_X=5; win1_Y=24; win1_W=639; win1_H=499;
win2_X=642; win2_Y=24; win2_W=639; win2_H=499;
win3_X=1280; win3_Y=24; win3_W=639; win3_H=499;
win4_X=5; win4_Y=552; win4_W=639; win4_H=499;
ChromesAvailable()
{
CA=$(wmctrl -lx | grep Chromium | wc -l)
}
GetNumOfChrome()
{
WID=$(wmctrl -l | grep n | awk '{print$1}')
#echo "INFO: window id = $WID"
}
PlaceWindow()
{
X=${n}_X; Y=${n}_Y; W=${n}_W; H=${n}_H;
wmctrl -i -r "$WID" -e $G,${!X},${!Y},${!W},${!H}
}
if [ "$#" -gt 0 ]; then
case "$1" in
*)
echo "ERROR: invalid option $1"
echo "see --help for usage"
exit 1
;;
esac
exit 0
else
for n in win{1..4}; do
GetNumOfChrome
PlaceWindow
done
fi
已编辑-为了更好地解释事情:-)
使用grep n
将加载系统上每个打开的窗口,因此我尝试使用,grep Chromimum
但脚本不喜欢这样
GetNumOfChrome()
{
WID=$(wmctrl -l | grep n | awk '{print$1}')
#echo "INFO: window id = $WID"
}
答案1
下面的脚本将在 Nx2 网格(N 行,2 列)中平铺任意数量的 chrome 或 chromium 窗口,其中 N 取决于打开的窗口数量。如果只有一个窗口,则该窗口将最大化(如果已经最大化,则取消最大化)。
#!/usr/bin/env bash
#################################################
# Exit if there are no running chrome processes #
#################################################
pgrep "chrom[e|ium]" &>/dev/null ||
echo "No Chrom[e|ium] processes are running" 1>&2 && exit
#########################
# Get screen dimensions #
#########################
read width x height < <(xrandr | grep -Po 'current\s*\K.*?(?=,)' )
###################################################################
# Get the names of all Chrome windows. I am using PIDs because #
# searching by name will match anything with chrome/chromium in #
# the title, not only chromium windows. It also matches a firefox #
# window open on this AU question, for example. #
###################################################################
mapfile -t windows <
<(wmctrl -pl | grep -f <(pgrep "chrom[e|ium]") |
cut -d' ' -f1)
####################################
# Get the number of Chrome windows #
####################################
numofwins=${#windows[@]}
#########################################
# Initialize the x and y positions to 0 #
#########################################
x=0
y=0
#############################################
# Get 1/2 the number of windows, rounded up #
#############################################
halfwins=$(printf "%.f" "$(echo $numofwins/2 | bc -l |
awk '{print int($1+0.5)}')")
######################################################
# If there's only one window, maximize/unmaximize it #
######################################################
[[ $numofwins -eq 1 ]] &&
wmctrl -i -r "${windows[@]}" -b toggle,maximized_vert,maximized_horz &&
exit;
##########################################################################
# The height of each window will be the height of the display divided by #
# half the number of windows #
##########################################################################
winheight=$(printf "%.f" "$(echo $height/$halfwins | bc -l)")
##################################################################
# The width of each window will be half the width of the display #
##################################################################
winwidth=$(($width/2))
##################################
# Iterate over each window found #
##################################
for winID in "${windows[@]}"
do
########################################
# Increment a counter. This is used to #
# know when we should change rows. #
########################################
let c++
###############################
# Position the current window #
###############################
wmctrl -i -r "$winID" -e 0,$x,$y,$winwidth,$winheight
##################################################
# If the counter is a multiple of 2, change rows #
##################################################
if [[ $((c % 2)) -eq 0 ]]
then
y=$((y+$winheight+2))
x=0
#######################################
# If it isn't, move to the right only #
#######################################
else
x=$((x+$winwidth+2))
fi
done
答案2
另一种方法是将窗口排列成预定义(可定制)的网格(列/行)
一个例子:
重新排列为(cols
设置为 3,rows
设置为 2):
重新排列为(cols
设置为 4,rows
设置为 2):
下面的脚本可用于执行此操作。如前所述,可以设置列数和行数,以及窗口之间的填充。然后脚本计算窗口应排列到的位置以及它们的大小。
在 Unity 上使用 wmctrl 命令
wmctrl
当用于将窗口移动到启动器或面板附近时,该命令会显示一些特殊之处。因此,边距:
left_margin = 70; top_margin = 30
不能设置为零。您必须与面板和启动器保持至少几个像素的距离。我建议保留边距值。所有其他值、填充、列和行,您可以随意设置。
剧本
#!/usr/bin/env python3
import subprocess
import getpass
import sys
#--- set your preferences below: columns, rows, padding between windows, margin(s)
cols = 2; rows = 2; padding = 10; left_margin = 70; top_margin = 30
#---
get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_res():
xr = get("xrandr").split(); pos = xr.index("current")
return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
# get resolution
res = get_res()
# define (calculate) the area to divide
area_h = res[0] - left_margin; area_v = res[1] - top_margin
# create a list of calculated coordinates
x_coords = [int(left_margin+area_h/cols*n) for n in range(cols)]
y_coords = [int(top_margin+area_v/rows*n) for n in range(rows)]
coords = sum([[(cx, cy) for cx in x_coords] for cy in y_coords], [])
# calculate the corresponding window size, given the padding, margins, columns and rows
w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
# find windows of the application, identified by their pid
pids = [p.split()[0] for p in get("ps -e").splitlines() if sys.argv[1] in p]
w_list = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if p in w] for p in pids], [])
print(pids, w_list, coords)
# remove possibly maximization, move the windows
for n, w in enumerate(w_list):
data = (",").join([str(item) for item in coords[n]])+","+(",").join(w_size)
cmd1 = "wmctrl -ir "+w+" -b remove,maximized_horz"
cmd2 = "wmctrl -ir "+w+" -b remove,maximized_vert"
cmd3 = "wmctrl -ir "+w+" -e 0,"+data
for cmd in [cmd1, cmd2, cmd3]:
subprocess.Popen(["/bin/bash", "-c", cmd])
如何使用
- 确保
wmctrl
已安装:) - 将脚本复制到一个空文件中,保存为
rearrange_windows.py
- 在脚本的头部,设置你的偏好
通过命令运行:
python3 /path/to/rearrange_windows.py <application>
例如:重新排列
chromium
窗口:python3 /path/to/rearrange_windows.py chromium
重新排列
chrome
窗口python3 /path/to/rearrange_windows.py chrome
笔记
该脚本可用于将任何应用程序的窗口放入网格中,因为进程名称应用程序用作参数。
编辑
动态版本
下面是一个动态版本的脚本,如评论中所要求的。此版本的脚本根据窗口数量计算列数和行数。重新排列的窗口的比例与屏幕的比例相似。
设置和使用与上面的版本几乎相同,只是现在自动设置列数和行数。
#!/usr/bin/env python3
import subprocess
import getpass
import sys
import math
#--- set your preferences below: padding between windows, margin(s)
padding = 10; left_margin = 70; top_margin = 30
#---
get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_res():
xr = get("xrandr").split(); pos = xr.index("current")
return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
# find windows of the application, identified by their pid
pids = [p.split()[0] for p in get("ps -e").splitlines() if sys.argv[1] in p]
w_list = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if p in w] for p in pids], [])
# calculate the columns/rows, depending on the number of windows
cols = math.ceil(math.sqrt(len(w_list))); rows = cols
# define (calculate) the area to divide
res = get_res()
area_h = res[0] - left_margin; area_v = res[1] - top_margin
# create a list of calculated coordinates
x_coords = [int(left_margin+area_h/cols*n) for n in range(cols)]
y_coords = [int(top_margin+area_v/rows*n) for n in range(rows)]
coords = sum([[(cx, cy) for cx in x_coords] for cy in y_coords], [])
# calculate the corresponding window size, given the padding, margins, columns and rows
if cols != 0:
w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
# remove possibly maximization, move the windows
for n, w in enumerate(w_list):
data = (",").join([str(item) for item in coords[n]])+","+(",").join(w_size)
cmd1 = "wmctrl -ir "+w+" -b remove,maximized_horz"
cmd2 = "wmctrl -ir "+w+" -b remove,maximized_vert"
cmd3 = "wmctrl -ir "+w+" -e 0,"+data
for cmd in [cmd1, cmd2, cmd3]:
subprocess.call(["/bin/bash", "-c", cmd])
请参见以下打开的窗口数量不同的示例:
解释(第二个脚本)
查找特定窗口
命令:
wmctrl -lp
列出所有窗口,格式为:
0x19c00085 0 14838 jacob-System-Product-Name *Niet-opgeslagen document 1 - gedit
其中第一列是窗口的唯一 id,第三列是拥有该窗口的应用程序的 pid。
命令:
ps -e
列出所有进程,格式为:
14838 ? 00:00:02 gedit
其中第一列是应用程序的 pid,最后一列是进程名称。
通过比较这两个列表,我们可以找到属于特定应用程序的所有窗口(id of-)(
w_list
在脚本中调用,作为脚本中第 17/18 行的结果):pids = [p.split()[0] for p in get("ps -e").splitlines() if sys.argv[1] in p] w_list = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if p in w] for p in pids], [])
计算行数/列数
- 如果我们将窗口制作成与屏幕相同比例,则意味着列数等于行数。
这意味着列数和行数都等于要重新排列的窗口数的四舍五入平方根。这在第 20 行完成:
cols = math.ceil(math.sqrt(len(w_list))); rows = cols
计算窗口大小和位置
一旦我们有了列数,我们所需要做的就是将可用区域(屏幕分辨率 - 左边距/上边距)划分为列/行,然后我们就得到了目标窗口大小
padding
,然后按脚本头部所设置的减少:w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
这水平(x)位置是水平窗口大小(包括填充)乘以列数,在列数范围内。例如:如果我有 3 列,每列 300 像素,则得到的 x 位置为:
[0, 300, 600]
这垂直(y)位置计算方法与此类似。然后将两个列表组合成一个坐标列表,窗口将在该列表中重新排列。
这是在脚本的第 26-28 行完成的:
x_coords = [int(left_margin+area_h/cols*n) for n in range(cols)] y_coords = [int(top_margin+area_v/rows*n) for n in range(rows)] coords = sum([[(cx, cy) for cx in x_coords] for cy in y_coords], [])
实际的重新排列最终(在取消最大化或最大化的窗口之后)从第 33 行及以后完成。