如何启动具有预定义窗口大小和位置的应用程序?
我想知道是否有任何方法可以使用终端命令来实现Unity中Ctrl-Alt-Keypad快捷方式的影响? 我想要一个命令,将gui窗口设置为屏幕大小的一半,左右对齐。
作为背景,我正在编写一个在登录后运行的脚本。它使用Zenity来询问我是否要打开我的开发环境(GVim和IPython并排)。 我一直在尝试使用我的.gvimrc
set lines= columns=
和我的c.IPythonWidget.width =
和c.IPythonWidget.height =
来为这些程序实现两个大小相等的窗口。 但是,这种方法存在一些问题。
你将遇到什么
如果要首先调用应用程序,然后将其窗口放在特定的位置和大小上,则调用应用程序与窗口实际显示之间的时间是不可预测的。 如果您的系统被占用,它可能比空闲时长得多。
您需要一种“智能”方式来确保在窗口出现后立即完成定位/resize。
用于调用应用程序的脚本,等待它出现并将其放置在屏幕上
使用下面的脚本,您可以使用以下命令调用应用程序并设置应显示的位置和大小:
几个例子:
-
要调用
gnome-terminal
并将其窗口大小调整为50%并将其放在右半边: -
要调用
gedit
,将其窗口放在左侧并调用gnome-terminal
,将其放在右侧(将其v-size
设置为46%以在窗口之间留出一点空间): -
要调用Inkscape,请将其窗口放在屏幕的左上角/上四分之一处:
该脚本以及如何使用它
-
安装
xdotool
和wmctrl
。 我使用了两者,因为使用wmctrl
resize会导致(特别是)Unity
某些特性。sudo apt-get install wmctrl sudo apt-get install xdotool
- 将下面的脚本复制到一个空文件中,将其保存为
~/bin
setwindow
(无扩展名); 必要时创建目录。 - 使脚本可执行(!)
- 如果刚刚创建了
~bin
,请运行:source ~/.profile
-
使用命令测试脚本(例如)
setwindow gnome-terminal 0 0 50 100
换一种说法:
setwindow
如果一切正常,请在任何需要的地方使用命令。
剧本
#!/usr/bin/env python3 import subprocess import time import sys app = sys.argv[1] get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8") ws1 = get("wmctrl -lp"); t = 0 subprocess.Popen(["/bin/bash", "-c", app]) while t < 30: ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1] procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \ if app in p and w[2] in p] for w in ws2] if len(procs) > 0: w_id = procs[0][0][1] cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz" cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert" cmd3 = "xdotool windowsize --sync "+procs[0][0][1]+" "+sys.argv[4]+"% "+sys.argv[5]+"%" cmd4 = "xdotool windowmove "+procs[0][0][1]+" "+sys.argv[2]+" "+sys.argv[3] for cmd in [cmd1, cmd2, cmd3, cmd4]: subprocess.call(["/bin/bash", "-c", cmd]) break time.sleep(0.5) t = t+1
它能做什么
调用脚本时,它:
- 启动应用程序
- 密切关注窗口列表(使用
wmctrl -lp
) - 如果出现一个新窗口,它会检查新窗口是否属于被调用的应用程序(使用
ps -ef ww
,将窗口的pid与应用程序的pid进行比较) - 如果是这样,它根据你的论点设定大小和位置。 如果应用程序没有“显示”在appr内。 15秒后,该脚本假定应用程序由于错误而无法运行。 然后脚本终止以防止无限地等待新窗口。
小问题
在Unity中,当您使用wmctrl
或xdotool
(重新)定位和(重新)调整窗口大小时,除非将其设置为100%,否则窗口将始终保持对屏幕边框的小幅度。 你可以在上面的图像(3)中看到; 当inkscape
窗口放在x
位置0时,你仍然可以在Unity Launcher和inkscape
窗口之间看到一个小问题。
我已经为Unity构建了一个名为Worksets(在github上 )的应用程序,它允许您通过图形用户界面轻松完成 – 它是免费和开源的。
它基本上是作为答案列出的wmctrl和xdotool解决方案的包装器,并提供了一种快速制作和保存此类设置的简便方法。
你想要的实际命令是这样的
wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,0,0,$HALF,-1
这将使当前窗口占据屏幕的一半(将$HALF
更改$HALF
屏幕尺寸)并捕捉到左侧。 要向右捕捉,请使用
wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$HALF,0,$HALF,-1
您还可以使用wmctrl
来获取您感兴趣的窗口的ID,而不是使用:ACTIVE:
. 我无法帮助那里,因为那取决于有问题的窗户。 看看man wmctrl
了解更多。
我已经写了一个脚本。 我不使用Unity,所以我无法保证它能与它一起工作,但我认为没有理由不这样做。 它需要安装wmctrl
, xdpyinfo
和wmctrl
:
sudo apt-get install wmctrl x11-utils disper
然后,将下面的脚本保存为~/bin/snap_windows.sh
,使用chmod a+x ~/bin/snap_windows.sh
使其可执行,然后就可以运行
snap_windows.sh r
要按到右侧。 在左侧使用l
,没有参数来最大化窗口。 请注意,它在当前窗口上运行,因此如果您希望它在除终端之外的任何其他设备上运行,则需要为其指定快捷方式。
该脚本比您要求的要复杂得多,因为我已将其编写为适用于单显示器和双显示器设置。
#!/usr/bin/env bash ## If no side has been given, maximize the current window and exit if [ ! $1 ] then wmctrl -r :ACTIVE: -b toggle,maximized_vert,maximized_horz exit fi ## If a side has been given, continue side=$1; ## How many screens are there? screens=`disper -l | grep -c display` ## Get screen dimensions WIDTH=`xdpyinfo | grep 'dimensions:' | cut -f 2 -d ':' | cut -f 1 -d 'x'`; HALF=$(($WIDTH/2)); ## If we are running on one screen, snap to edge of screen if [ $screens == '1' ] then ## Snap to the left hand side if [ $side == 'l' ] then ## wmctrl format: gravity,posx,posy,width,height wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,0,0,$HALF,-1 ## Snap to the right hand side else wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$HALF,0,$HALF,-1 fi ## If we are running on two screens, snap to edge of right hand screen ## I use 1600 because I know it is the size of my laptop display ## and that it is not the same as that of my 2nd monitor. else LAPTOP=1600; ## Change this as approrpiate for your setup. let "WIDTH-=LAPTOP"; SCREEN=$LAPTOP; HALF=$(($WIDTH/2)); if [ $side == 'l' ] then wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$LAPTOP,0,$HALF,-1 else let "SCREEN += HALF+2"; wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$SCREEN,0,$HALF,-1; fi fi
您可以使用xdotool
执行此操作。
要安装xdotool
您可以运行:
sudo apt-get update && sudo apt-get install xdotool
然后将Ctrl + Alt + X
窗口,您可以运行:
xdotool key Ctrl+Alt+
*
要运行GUI程序并将键xdotool
送到其X
窗口(在本例中是执行xdotool
命令时的活动窗口),您可以运行:
&& window="$(xdotool getactivewindow)" xdotool key --delay --window "$window"
*
请注意,在大多数情况下,您需要运行您作为独立进程发出的命令(例如,通过在上面的示例中运行nohup
而不是
),否则将无法运行xdotool
直到
的执行完成。
此外,您还需要设置一些延迟,否则在目标窗口完全加载到X
之前将发送击键(应该延迟大约500ms
)。
的可能值为:
-
90
-
87
-
88
-
89
-
83
-
84
-
85
-
79
-
80
-
81
作为一个拇指规则,要找出X
环境中键盘上任何键的值,可以运行xev
并按下键以在终端内输出其值。
我没有代表直接评论Jacob Vlijm的优秀post,但我修改了脚本以允许启动带参数的应用程序(使用setwindow
和gedit --new-window
setwindow
gedit --new-window
必需的)。 更改:
if app in p and w[2] in p] for w in ws2]
至:
if app.split()[0] in p and w[2] in p] for w in ws2]
我从上面玩了Terdon的脚本并添加了一些新东西(能够选择监视器并为每个监视器设置高度)。 我认为增加更多的显示器是可以扩展的。 希望其他人会发现它很有用。
基本语法:
prog_name monitor l/r/m window_name (optional)
其中prog_name是您保存此代码的任何内容; 监视器是监视器编号,例如1或2; l / r / m是左或右或最大; 和window_name是目标窗口的名称(或其名称的一小部分)。
例如:
setwindow 1 m chrome
Bash脚本
#!/usr/bin/env bash set -e #######################- Early Definitions -####################### snap () { wmctrl -r ${WIN} -b toggle,add,maximized_vert && wmctrl -r ${WIN} -e 0,${WINX},0,${WINWIDTH},${WINHEIGHT} } DISPLAYWIDTH=`xdpyinfo | grep 'dimensions:' | cut -f 2 -d ':' | cut -f 1 -d 'x'`; ## Get screen dimensions LEFTSCREENWIDTH=1024 ## user set LEFTSCREENHEIGHT=720 ## user set RIGHTSCREENHEIGHT=960 ## user set let "RIGHTSCREENWIDTH=(DISPLAYWIDTH-LEFTSCREENWIDTH)" #############################- Logic -############################# if [ ! ${3} ]; then WIN=":ACTIVE:" else WIN=${3} fi case ${1} in 1) # monitor one LEFT=0 WINHEIGHT=${LEFTSCREENHEIGHT} let "WINWIDTH=LEFTSCREENWIDTH/2" ;; 2) # monitor two let "LEFT=LEFTSCREENWIDTH" WINHEIGHT=${RIGHTSCREENHEIGHT} let "WINWIDTH=RIGHTSCREENWIDTH/2" ;; "") # error please select a monitor echo "please select a monitor (1 or 2)" exit 0 ;; esac case ${2} in l|L) WINX=${LEFT} snap ;; r|R) let "WINX=LEFT+WINWIDTH" snap ;; ""|m|M) WINX=${LEFT} let "WINWIDTH=WINWIDTH*2" snap ;; esac exit 0