当前位置: 首页>>技术教程>>正文


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

, , ,

问题描述

我想知道是否有任何方法可以使用终端命令来实现 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

脚本及其使用方法

  1. 安装 xdotoolwmctrl 。我同时使用了两者,因为使用 wmctrl 调整大小可能会导致(特别是) Unity 出现一些特殊情况。

    \n

    sudo apt-get install wmctrl\nsudo apt-get install xdotool\n
  2. 将下面的脚本复制到一个空文件中,在 ~/bin 中保存为 setwindow(无扩展名);如有必要,创建目录。

  3. 使脚本可执行(!)

  4. 如果您刚刚创建了 ~bin ,请运行:source ~/.profile

  5. 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

它能做什么

调用脚本时,它:

  1. 启动应用程序

  2. 密切关注窗口列表(使用 wmctrl -lp )

  3. 如果出现新窗口,它会检查新窗口是否属于被调用的应用程序(使用 ps -ef ww ,将窗口的 pid 与应用程序的 pid 进行比较)

  4. 如果是这样,它会根据您的参数设置大小和位置。\n如果应用程序不在 appr 内 “show up”。 15 秒后,脚本假定应用程序将因错误而无法运行。然后脚本终止以防止无限等待新窗口。

小问题

在 Unity 中,当您使用 wmctrlxdotool 来(重新)定位和(重新)调整窗口大小时,除非您将其设置为 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,所以我不能保证它会与它一起工作,但我没有理由不这样做。它需要安装 wmctrlxdpyinfodisper

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 并按下该键以在终端内输出其值。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/13619.html,未经允许,请勿转载。