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


22

我想知道有什么方法可以使用终端命令代替Unity中的Ctrl-Alt-Keypad快捷键吗?我想要一个将gui窗口设置为屏幕大小一半(左对齐或右对齐)的命令。

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


我更新了我的答案,因为它没有足够详细地解释该主题,您可能需要检查更新
kos 2015年

Answers:


17

你会遇到什么

如果要先调用应用程序,然后将其窗口放置在特定的位置和大小上,则调用该应用程序该窗口实际出现之间的时间是不可预测的。如果您的系统已被占用,则它可能比空闲状态更长。

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

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

在下面的脚本中,您可以调用一个应用程序,并使用以下命令设置应在其中显示的位置和大小:

<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. 如果是这样,它会根据您的参数设置大小和位置。如果应用程序未在appr中“显示”。15秒后,脚本假定应用程序由于错误而无法运行。然后脚本终止,以防止无限期地等待新窗口。

次要问题

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


亲爱的雅各布,这是一个很棒的剧本!一个问题:如何找到要与脚本一起使用的打开窗口的尺寸?
orschiro 2016年

嗨@orschiro,我必须参加会议...几个小时后会回来的:)
Jacob Vlijm 2016年

1
@orschiro,您好,假设您已wmctrl安装,则命令:wmctrl -lG | grep <windowname>将显示类似以下的输出 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit。在此输出中,第3列到第6列显示尺寸x,y,宽度,宽度,高度。
Jacob Vlijm '16

非常感谢雅各!我想我正确地进行了设置,但是相应的窗口现在已在全屏模式下打开。有任何想法吗?
orschiro 2016年

1
我喜欢这个脚本,但是我必须对第一个块进行以下更改以使其对我起作用,因为我向应用程序添加了参数: appAndParams = sys.argv[1] app = appAndParams[0].split(' ', 1)[0] get = lambda x: subprocess.check_output(["/bin/bash", "-c",x]).decode("utf-8") ws1 = get("wmctrl -lp"); t = 0 subprocess.Popen(["/bin/bash", "-c", appAndParams])</ pre> <edit>它拒绝格式化该代码。</ edit>
罗恩·汤普森

3

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

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>

另外,您还需要设置一些延迟,否则击键将在目标窗口完全加载之前发送X500ms应该延迟一下)。

可能的值为<keypad_key_value>

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

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


我们的编辑有问题吗?
蒂姆(Tim)

@Tim不,至少不要删除最后一行,我同意这是没有用的,但是在我看来,如果用尖括号括起来,则命令中可以更改的格式会更好,这是语言理论中引用的标准符号归类为语法类别(请参阅您的编辑),我认为最好将命令名称格式放在反引号中,以便立即将其识别出来(请参阅AB的编辑);请注意,并不是所有的事情都在我的脑海中浮现,我之前对此表示怀疑,我在meta上问了这些问题
kos 2015年

是的,现在还好:) <>是标准设置,我赞成``围绕任何命令:)
Tim

3

我已经为Unity 构建了一个名为Worksets的应用程序(在github上),该应用程序可让您通过图形用户界面轻松进行此操作-它是免费的开放源代码。

tTray菜单

它基本上是这里列出的答案的wmctrl和xdotool解决方案的包装,并提供了一种快速进行和保存此类设置的简便方法。


1

我没有直接代表雅各上Vlijm出色的帖子发表评论,但我修改剧本,以允许开始参数(需要使用的应用程序setwindowgedit --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]

0

我从上面玩过Terdon的脚本,并添加了一些新内容(可以选择监视器并为每个监视器设置高度)。我认为可以扩展到添加更多的监视器。希望其他人会发现它有用。

基本语法:

prog_name monitor l/r/m window_name (optional)

其中,prog_name是将代码保存为的位置;monitor是监视器编号,例如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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.