Як запустити програму із заздалегідь визначеним розміром та позицією вікна?


22

Мені цікаво, чи є якийсь спосіб досягти впливу клавіш Ctrl-Alt-клавіатури в Unity, використовуючи замість цього термінальні команди? Я хочу команду, яка встановлює вікно gui в половину розміру екрана, ліворуч або праворуч вирівняне.

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


Я оновив свою відповідь, оскільки вона не пояснила тему досить детально, ви можете перевірити оновлення
kos

Відповіді:


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. встановити і xdotoolі wmctrl. Я використовував обидва, оскільки зміна розміру з 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 секунд сценарій припускає, що програма не запуститься через помилку. Потім сценарій припиняється, щоб запобігти чеканню нового вікна нескінченно.

Незначне питання

У Unity, коли ви (повторно) позиціонуєте та (повторно) розмірите вікно з будь-яким wmctrlабо xdotool, воно завжди буде мати невеликий мардж до меж вашого екрана, якщо ви не встановите його на 100%. Ви можете бачити це на зображенні (3) вище; Поки inkscapeвікно було розміщене на xпозиції 0, ви все ще можете побачити незначний мардж між пусковою ланкою Unity та inkscapeвікном.


Шановний Якобе, це фантастичний сценарій! Одне запитання: як я можу знайти розмірність відкритого вікна, яке згодом використовуватиметься разом із сценарієм?
orschiro

Привіт @orschiro Мені потрібно побігти на зустріч ... повернемось через кілька годин :)
Якоб Влійм,

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, ширину, ширину, висоту.
Яків Влійм

Дуже цінуємо Якова! Я думаю, що я зробив налаштування правильно, але зараз відповідне вікно відкривається в повноекранному режимі. Будь-які ідеї?
orschiro

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щоб отримати ідентифікатор вікон, які вас цікавлять, а не використовувати :ACTIVE:. Я не можу допомогти там, хоча це залежить від Windows. Подивіться 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

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>:

  • 0: 90
  • 1: 87
  • 2: 88
  • 3: 89
  • 4: 83
  • 5: 84
  • 6: 85
  • 7: 79
  • 8: 80
  • 9: 81

Як правило, щоб дізнатись значення будь-якої клавіші на клавіатурі в Xоточенні, можна запустити xevта натиснути клавішу, щоб вивести її значення всередині терміналу.


Чи щось не в порядку з нашими правками?
Тім

@Tim Ні, принаймні, не видалення останнього рядка, який, я погоджуюсь, є досить непридатним, але те, що може змінюватися в межах команди, на мій погляд, краще відформатувати, якщо укладено в кутових дужках, що є стандартним позначенням в теорії мови для посилання до синтаксичної категорії (з посиланням на вашу редагування), і я вважаю, що ім'я команди краще відформатувати, якщо укладено в задні посилання, щоб бути негайно визнаним таким (маючи на увазі редагування AB); зауважте, що не все це у верхній частині моєї голови, у мене були сумніви раніше, і я запитав це на мета
kos

Так, це нормально, як зараз :) <> це стандарт, і я йду за `` навколо будь-якої команди :)
Тім

3

Я створив додаток під назвою Worksets (на github ) для Unity, який дозволяє вам це легко робити через графічний інтерфейс користувача - це безкоштовно та з відкритим кодом.

tTray меню

Це в основному обгортка для рішень wmctrl та xdotool, перелічених тут як відповіді, і забезпечує простий спосіб швидко зробити та зберегти такі налаштування.


1

У мене немає респ безпосередньо коментувати відмінний пост Якоба Vlijm, але я змінив сценарій , щоб дозволити запуск програми з аргументами (необхідно використовувати 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]

0

Я пограв зі сценарієм Тердона зверху і додав нові речі (можливість вибору монітора та встановлення висоти для кожного монітора). Я думаю, можна додати більше моніторів. Сподіваємось, інші знайдуть це корисним.

Основний синтаксис:

prog_name monitor l/r/m window_name (optional)

Де prog_name - це те, що ви зберегли цей код; монітор - номер монітора, наприклад, 1 або 2; l / r / m ліворуч або праворуч або max; і ім'я_назва - це ім'я (або частка його імені) цільового вікна.

Наприклад:

setwindow 1 m chrome

Баш сценарій

#!/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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.