如何找到特定应用程序的窗口并将它们放入网格中?

我正在尝试编写一个脚本来识别所有打开的镀铬窗口,并将它们移动到大屏幕上的网格布局中

我不知道如何找出最佳分辨率是什么,所以我要手动将它们添加到一个数组中,这样如果有1个镀铬窗口可用,那么最大化,如果有2个镀铬窗口可用,那么就转到一个数组大小为了那个原因?

目前我可以移动屏幕上的每个窗口(这样做时会破坏我的显示)但我可以看到如何移动只有铬屏幕?

下面的脚本是我的一些想法,但请指出正确的方向,因为脚本不起作用

#!/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" } 

另一种方法是将窗口排列成预定义(可自定义)的网格(列/行)

一个例子:

在此处输入图像描述

重新排列为( cols设置为3, rows设置为2):

在此处输入图像描述

重新排列为( cols设置为4, rows设置为2):

在此处输入图像描述

下面的脚本可用于执行此操作。 如上所述,可以设置列数和行数,以及窗口之间的填充。 该脚本然后计算窗口应该排列的位置,以及它们的大小。

在Unity上使用wmctrl命令

当用于将窗口移动到发射器或面板附近或非常靠近发射器或面板时, wmctrl命令显示一些特性。 因此边际:

 left_margin = 70; top_margin = 30 

不能设置为零。 你必须与面板和发射器保持至少几个px的距离。 我建议保留两个边距值。 您可以使用的所有其他值,填充,列和行,并根据需要进行设置。

剧本

 #!/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]) 

如何使用

  1. 确保安装了wmctrl 🙂
  2. 将thye脚本复制到空文件中,将其保存为rearrange_windows.py
  3. 在脚本的head部分中,设置首选项
  4. 通过命令运行它:

     python3 /path/to/rearrange_windows.py  

    示例:重新排列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]) 

请参阅下面的示例,其中打开的窗口数量不同:

在此处输入图像描述在此处输入图像描述

在此处输入图像描述在此处输入图像描述

说明(第二个脚本)

找到特定的窗口

  1. 命令:

     wmctrl -lp 

    列出所有窗口,格式为:

     0x19c00085 0 14838 jacob-System-Product-Name *Niet-opgeslagen document 1 - gedit 

    其中第一列是窗口的唯一ID,第三列是拥有该窗口的应用程序的pid。

  2. 命令:

     ps -e 

    列出所有进程,格式为:

     14838 ? 00:00:02 gedit 

    第一列是应用程序的pid,最后一列是进程名称。

  3. 通过比较这两个列表,我们可以找到属于特定应用程序的所有窗口(id-)(在脚本中称为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], []) 

计算行数/列数

  1. 如果我们制作与屏幕相同比例的窗口,则表示列数等于行数。
  2. 这意味着colums和rows的数量都等于要重新排列的窗口数的四舍五入的平方根。 这是在第20行完成的:

     cols = math.ceil(math.sqrt(len(w_list))); rows = cols 

计算窗口大小和位置

  1. 一旦我们有了列数,我们需要做的就是在列/行中划分可用区域(屏幕分辨率 – 左边距/上边距),然后我们有目标窗口大小 ,然后padding减少,如设置在脚本的头部:

     w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))] 
  2. 水平(x)位置水平窗口大小 (包括填充)乘以列数的乘积的结果,在列数的范围内。 例如:如果我有3个300 px的列,则生成的x位置为:

     [0, 300, 600] 
  3. 同样计算垂直(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], []) 
  4. 最终的实际重新排列(在未最大化可能最大化的窗口之后)从线33进一步完成。

下面的脚本将在Nx2网格(N行,2列)中平铺任意数量的铬或铬窗口,其中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