问题描述
我想知道是否有任何方法可以使用终端命令来实现 Unity 中 Ctrl-Alt-Keypad 快捷方式的影响?我想要一个将 gui 窗口设置为屏幕大小的一半的命令,左对齐或右对齐。
作为背景,我正在编写一个在登录后运行的脚本。它使用 Zenity 询问我是否要打开我的开发环境(GVim 和 IPython side-by-side)。我一直在尝试通过在我的 .gvimrc
中使用 set lines= columns=
并在我的 ipython_qtconsole_config.py
中使用 c.IPythonWidget.width =
和 c.IPythonWidget.height =
来为这些程序实现两个 equal-sized 窗口。然而,这种方法存在一些问题。
最佳方案
你会遇到什么
如果您想首先调用应用程序,然后将其窗口放置在特定位置和大小,则调用应用程序和窗口实际出现之间的时间是不可预测的。如果您的系统被占用,它可能比空闲时长得多。
您需要 “smart” 方法来确保在窗口出现后(立即)完成定位/调整大小。
调用应用程序的脚本,等待它出现并将其定位在屏幕上
使用下面的脚本,您可以调用一个应用程序并使用命令设置它应该出现的位置和大小:
<script> <application> <x-position> <y-position> <h-size> <v-size>
几个例子:
-
要调用
gnome-terminal
并将其窗口大小调整为 50% 并将其放在右半边:\n
<script> gnome-terminal 840 0 50 100\n
\n
-
要调用
gedit
,将其窗口放在左侧并调用gnome-terminal
,将其放在右侧(将其v-size
设置为 46% 以在窗口之间留出一点空间):\n
<script> gedit 0 0 46 100&&<script> gnome-terminal 860 0 46 100\n
\n
-
要调用 Inkscape,请将其窗口放在屏幕的左/上四分之一处:
\n
<script> inkscape 0 0 50 50\n
\n
脚本及其使用方法
-
安装
xdotool
和wmctrl
。我同时使用了两者,因为使用wmctrl
调整大小可能会导致(特别是)Unity
出现一些特殊情况。\n
sudo apt-get install wmctrl\nsudo apt-get install xdotool\n
-
将下面的脚本复制到一个空文件中,在
~/bin
中保存为setwindow
(无扩展名);如有必要,创建目录。 -
使脚本可执行(!)
-
如果您刚刚创建了
~bin
,请运行:source ~/.profile
-
Test-run 带有命令的脚本(例如)
\n
setwindow gnome-terminal 0 0 50 100\n
\n
换句话说:
\n
setwindow <application> <horizontal-position> <vertical-position> <horizontal-size (%)> <vertical-size (%)>\n
如果一切正常,请在需要的地方使用该命令。
剧本
#!/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 进行比较) -
如果是这样,它会根据您的参数设置大小和位置。\n如果应用程序不在 appr 内 “show up”。 15 秒后,脚本假定应用程序将因错误而无法运行。然后脚本终止以防止无限等待新窗口。
小问题
在 Unity 中,当您使用 wmctrl
或 xdotool
来(重新)定位和(重新)调整窗口大小时,除非您将其设置为 100%,否则该窗口将始终与屏幕边界保持一小段距离。您可以在上面的图片 (3) 中看到;虽然 inkscape
窗口被放置在 x
位置 0,但您仍然可以看到 Unity Launcher 和 inkscape
窗口之间的小边界。
次佳方案
你想要的实际命令是这样的
wmctrl -r :ACTIVE: -b add,maximized_vert &&
wmctrl -r :ACTIVE: -e 0,0,0,$HALF,-1
这将使当前窗口占据屏幕的一半(将 $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
和 disper
:
sudo apt-get install wmctrl x11-utils disper
然后,将下面的脚本保存为 ~/bin/snap_windows.sh
,使用 chmod a+x ~/bin/snap_windows.sh
使其可执行,然后您可以运行
snap_windows.sh r
捕捉到右侧。在左侧使用 l
并且不使用任何参数来最大化窗口。请注意,它在当前窗口上运行,因此如果您希望它在终端以外的任何地方运行,您需要为其分配一个快捷方式。
该脚本比您要求的要复杂一些,因为我编写它是为了在单一和 dual-monitor 设置上工作。
#!/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
第三种方案
我已经为 Unity 构建了一个名为 Worksets(在 github 上)的应用程序,它可以让您通过图形用户界面轻松地做到这一点——它是免费和开源的。
它基本上是此处列为答案的 wmctrl 和 xdotool 解决方案的包装器,并提供了一种快速制作和保存此类设置的简便方法。
第四种方案
您可以使用 xdotool
执行此操作。
要安装 xdotool
,您可以运行:
sudo apt-get update && sudo apt-get install xdotool
然后将 Ctrl
+ Alt
+ <keypad_key>
击键发送到终端 X
窗口,您可以运行:
xdotool key Ctrl+Alt+<keypad_key_value>
*; = 下面列表中的键盘键值
要运行 GUI 程序并将击键发送到其 X
窗口(在本例中为 xdotool
命令执行时的活动窗口),您可以运行:
<command> && window="$(xdotool getactivewindow)" xdotool key --delay <delay> --window "$window" <keypad_key_value>
*; = 打开您要将击键发送到的窗口的命令; = 发送击键前等待的时间,以毫秒为单位; ; = 下面列表中的键盘键值
请注意,在大多数情况下,您需要运行作为 stand-alone 进程发出的命令(例如,通过运行 nohup <command> &
而不是上例中的 <command>
),否则 xdotool
将不会运行,直到 <command>
的执行完成。
此外,您还需要设置一些延迟,否则击键将在目标窗口完全加载到 X
之前发送(应该在 500ms
附近延迟)。
<keypad_key_value>
的可能值为:
-
0
:90
-
1
:87
-
2
:88
-
3
:89
-
4
:83
-
5
:84
-
6
:85
-
7
:79
-
8
:80
-
9
:81
作为经验法则,要找出 X
环境中键盘上任意键的值,可以运行 xev
并按下该键以在终端内输出其值。