Как я могу запустить приложение с заранее определенным размером и положением окна?

19

Мне интересно, есть ли способ добиться влияния клавиш Ctrl-Alt-Keypad в Unity с помощью команд терминала? Мне нужна команда, которая устанавливает окно gui на половину размера экрана, выравнивание влево или вправо.

В качестве фона я пишу скрипт, который запускается после входа в систему. Он использует Zenity, чтобы узнать, хочу ли я открыть среду разработки (GVim и IPython бок о бок). Я пытаюсь создать два окна равного размера для этих программ, используя set lines= columns= в моих .gvimrc и c.IPythonWidget.width = и c.IPythonWidget.height = в моем ipython_qtconsole_config.py . Однако есть проблемы, связанные с этим подходом.

    
задан STim 25.04.2015 в 17:48
источник

6 ответов

15

Что вы столкнетесь с

Если вы хотите сначала вызвать приложение и, впоследствии, поместить его окно в определенную позицию и размер, время между вызовом приложения и в момент появления окна , непредсказуем. Если ваша система занята, она может быть значительно длиннее, чем если она не работает.

Вам нужен «умный» способ убедиться, что позиционирование / изменение размера (сразу) после появления окна .

Сценарий для вызова приложения, дождитесь его появления и поместите его на экран

С помощью приведенного ниже сценария вы можете вызвать приложение и задать позицию и размер, которые должны появиться с помощью команды:

<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>gedit0046100&&<script>gnome-terminal860046100

  • Чтобы вызвать Inkscape, поместите его окно в левую / верхнюю четверть экрана:

    <script> inkscape 0 0 50 50
    

Сценарийиспособегоиспользования

  1. установитекакxdotool,такиwmctrl.Яиспользовалоба,таккакизменениеразмераспомощьюwmctrlможетвызватьнекоторыеособенности(вчастности)Unity.

    sudoapt-getinstallwmctrlsudoapt-getinstallxdotool
  2. Скопируйтесценарийнижевпустойфайл,сохранитеегокакsetwindow(безрасширения)в~/bin;принеобходимостисоздайтекаталог.
  3. Сделатьисполняемыйфайлсценария(!)
  4. Есливытолькочтосоздали~bin,запустите:source~/.profile
  5. Протестируйтескриптспомощьюкоманды(например.)

    setwindowgnome-terminal0050100

    Другимисловами:

    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 .

    
ответ дан Jacob Vlijm 26.04.2015 в 09:20
источник
4

У меня есть приложение с именем Worksets (на github ) для Unity, которое позволяет вам делать это легко через графический интерфейс пользователя - Это бесплатно и с открытым исходным кодом.

В основном это оболочка для решений wmctrl и xdotool, перечисленных здесь, и предоставляет простой способ быстро сделать и сохранить такие настройки.

    
ответ дан Tumult 10.07.2017 в 05:07
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 , чтобы получить идентификатор интересующих вас окон вместо использования :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 для левой стороны и никаких аргументов для максимизации окна. Обратите внимание, что он запускается в текущем окне, поэтому вам нужно назначить ему ярлык, если вы хотите, чтобы он работал на чем угодно, кроме терминала.

Сценарий немного сложнее, чем вы просите, потому что я написал его для работы как с одиночными, так и с двумя мониторами.

#!/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
    
ответ дан terdon 25.04.2015 в 18:35
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>

<суб> * < & команда GT; = команда, которая открывает окно, в которое вы хотите отправить нажатие клавиши; < задержка > = время ожидания в миллисекундах перед отправкой нажатия клавиши; < keypad_key_value > = значение клавиши клавиатуры в списке ниже

Обратите внимание, что в большинстве случаев вам нужно будет запустить команду, которую вы выпускаете как отдельный процесс (например, запустив nohup <command> & вместо <command> в примере выше), в противном случае xdotool won ' t будет выполняться до завершения выполнения <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 и нажать клавишу для вывода своего значения внутри терминала.

    
ответ дан kos 25.04.2015 в 17:55
1

У меня нет комментариев, чтобы прокомментировать это сообщение Джейкоба Влэйма, но я изменил сценарий, чтобы разрешить запуск приложения с аргументами (необходимо использовать 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]
    
ответ дан D. Hancock 13.05.2016 в 17:31
0

Я играл со сценарием 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
    
ответ дан Philosopher Rex 02.07.2018 в 09:49