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

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

我想知道是否有任何方法可以使用终端命令来实现 Unity 中 Ctrl-Alt-Keypad 快捷键的效果?我想要一个命令,将 GUI 窗口设置为屏幕大小的一半,左对齐或右对齐。

作为背景,我正在编写一个在登录后运行的脚本。它使用 Zenity 询问我是否要打开我的开发环境(并排的 GVim 和 IPython)。我一直试图通过在set lines= columns=我的.gvimrc和在我的中c.IPythonWidget.width =使用来实现这些程序的两个大小相同的窗口。但是,这种方法存在一些问题。c.IPythonWidget.height =ipython_qtconsole_config.py

答案1

你会遇到什么

如果你想先调用一个应用程序,然后将其窗口放置在特定的位置和大小,则调用应用程序窗口实际出现的那一刻,是不可预测的。如果您的系统处于繁忙状态,则该时间可能比空闲时长得多。

您需要一种“智能”的方法来确保定位/调整大小在窗口之后(立即)完成出现

调用应用程序的脚本,等待它出现并将其定位在屏幕上

使用下面的脚本,您可以调用一个应用程序并使用以下命令设置它应出现的位置和大小:

<script> <application> <x-position> <y-position> <h-size> <v-size>

举几个例子:

  • 调用gnome-terminal并调整其窗口大小为 50%,然后将其放置在右半部分:

    <script> gnome-terminal 840 0 50 100
    

    在此处输入图片描述

  • 要调用gedit,请将其窗口放在左侧调用gnome-terminal,将其放在右侧(设置其v-size46% 以在窗口之间留出一点空间):

    <script> gedit 0 0 46 100&&<script> gnome-terminal 860 0 46 100
    

    在此处输入图片描述

  • 要调用 Inkscape,请将其窗口放在屏幕的左侧/上部四分之一处:

    <script> inkscape 0 0 50 50
    

    在此处输入图片描述

脚本及其使用方法

  1. 安装xdotoolwmctrl。我使用了两个都因为调整大小wmctrl可能会导致(具体来说)出现一些特殊情况Unity

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

    setwindow gnome-terminal 0 0 50 100
    

    换句话说:

    setwindow <application> <horizontal-position> <vertical-position> <horizontal-size (%)> <vertical-size (%)>
    

如果一切正常,请在需要的地方使用该命令。

剧本

#!/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. 如果是,它会根据您的参数设置大小和位置。如果应用程序在大约 15 秒内没有“显示”,则脚本会假定该应用程序由于错误不会运行。然后脚本会终止,以防止无限期地等待新窗口。

小问题

wmctrl在 Unity 中,当您使用或(重新)定位和(重新)调整窗口大小时xdotool,窗口将始终与屏幕边框保持较小的间距,除非您将其设置为 100%。您可以在上图 (3) 中看到;当窗口inkscape放置在x位置 0 时,您仍然可以看到 Unity Launcher 和窗口之间的微小间距inkscape

答案2

你想要的实际命令是这样的

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,因此不能保证它能与 Unity 兼容,但我认为没有理由不兼容。它需要安装wmctrlxdpyinfo和: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用于左侧,不使用参数来最大化窗口。请注意,它在当前窗口上运行,因此如果您希望它在终端以外的任何窗口上运行,则需要为其分配快捷方式。

该脚本比您要求的要复杂一些,因为我编写它是为了在单显示器和双显示器设置上运行。

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

答案3

您可以使用 来执行此操作xdotool

要安装,xdotool您可以运行:

sudo apt-get update && sudo apt-get install xdotool

然后要将 ++ 按键发送Ctrl到终端窗口Alt,您可以运行:<keypad_key>X

xdotool key Ctrl+Alt+<keypad_key_value>

*<keypad_key_value> = 以下列表中的键盘键值

要运行 GUI 程序并将击键发送到其X窗口(在本例中是命令执行时的活动窗口xdotool),您可以运行:

<command> && window="$(xdotool getactivewindow)" xdotool key --delay <delay> --window "$window" <keypad_key_value>

*<command> = 打开要发送击键的窗口的命令;<delay> = 发送击键前等待的时间(以毫秒为单位);<keypad_key_value> = 下表中的键盘键值

请注意,在大多数情况下,您需要将发出的命令作为独立进程运行(例如,通过运行nohup <command> &而不是<command>在上面的示例中),否则直到执行完成xdotool才会运行。<command>

您还需要设置一些延迟,否则键击将在目标窗口完全加载之前发送X(大约延迟一下500ms就可以了)。

可能的值包括<keypad_key_value>

  • 090
  • 187
  • 288
  • 389
  • 483
  • 584
  • 685
  • 779
  • 880
  • 981

根据经验法则,要找出环境中键盘上任何键的值X,可以运行xev并按下该键以在终端内输出其值。

答案4

我没有权限直接评论 Jacob Vlijm 的精彩帖子,但我修改了脚本以允许使用参数启动应用程序(使用setwindowwith 时必须使用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]

相关内容