如何启动具有预定义窗口大小和位置的应用程序?

我想知道是否有任何方法可以使用终端命令来实现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,请将其窗口放在屏幕的左上角/上四分之一处:

      

    在此处输入图像描述

该脚本以及如何使用它

  1. 安装xdotoolwmctrl 。 我使用了两者,因为使用wmctrlresize会导致(特别是) Unity某些特性。

     sudo apt-get install wmctrl sudo apt-get install xdotool 
  2. 将下面的脚本复制到一个空文件中,将其保存为~/bin setwindow (无扩展名); 必要时创建目录。
  3. 使脚本可执行(!)
  4. 如果刚刚创建了~bin ,请运行: source ~/.profile
  5. 使用命令测试脚本(例如)

     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 

它能做什么

调用脚本时,它:

  1. 启动应用程序
  2. 密切关注窗口列表(使用wmctrl -lp
  3. 如果出现一个新窗口,它会检查新窗口是否属于被调用的应用程序(使用ps -ef ww ,将窗口的pid与应用程序的pid进行比较)
  4. 如果是这样,它根据你的论点设定大小和位置。 如果应用程序没有“显示”在appr内。 15秒后,该脚本假定应用程序由于错误而无法运行。 然后脚本终止以防止无限地等待新窗口。

小问题

在Unity中,当您使用wmctrlxdotool (重新)定位和(重新)调整窗口大小时,除非将其设置为100%,否则窗口将始终保持对屏幕边框的小幅度。 你可以在上面的图像(3)中看到; 当inkscape窗口放在x位置0时,你仍然可以在Unity Launcher和inkscape窗口之间看到一个小问题。

我已经为Unity构建了一个名为Worksets(在github上 )的应用程序,它允许您通过图形用户界面轻松完成 – 它是免费和开源的。

tTray菜单

它基本上是作为答案列出的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,所以我无法保证它能与它一起工作,但我认为没有理由不这样做。 它需要安装wmctrlxdpyinfowmctrl

 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,但我修改了脚本以允许启动带参数的应用程序(使用setwindowgedit --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