미리 정의 된 창 크기와 위치로 응용 프로그램을 시작하려면 어떻게해야합니까?


22

터미널 명령을 대신 사용하여 Unity에서 Ctrl-Alt-Keypad 단축키의 영향을 얻을 수있는 방법이 있는지 궁금합니다. GUI 창을 왼쪽 또는 오른쪽으로 정렬 된 화면 크기의 절반으로 설정하는 명령이 필요합니다.

배경으로, 나는 로그인 후 실행되는 스크립트를 작성하고 있습니다. Zenity를 사용하여 개발 환경 (GVim과 IPython을 나란히)을 열지 여부를 묻습니다. 내가 사용하여 이러한 프로그램에 대한 동일한 크기의 두 창을 달성하기 위해 노력 해왔다 set lines= columns=.gvimrcc.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-size창 사이에 약간의 공간을 두도록 46 % 설정 ).

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

    여기에 이미지 설명을 입력하십시오

  • Inkscape를 호출하려면 화면의 왼쪽 / 위쪽 분기에 창을 놓습니다.

    <script> inkscape 0 0 50 50

    여기에 이미지 설명을 입력하십시오

스크립트와 사용법

  1. 모두 설치 xdotool하고 wmctrl. 크기를 조정 하면 (특히) 약간의 특이성이 발생할 수 있기 때문에 두 가지를 모두 사용 했습니다 .wmctrlUnity

    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윈도우가 x0 위치에 있는 동안에도 Unity Launcher와 inkscape윈도우 간에 약간의 마지가 표시됩니다.


친애하는 야곱, 이것은 훌륭한 대본입니다! 한 가지 질문 : 스크립트와 함께 사용할 열린 창의 차원을 어떻게 찾을 수 있습니까?
orschiro

안녕하세요 @orschiro 나는 회의를 위해 실행해야합니다 ... 몇 시간 후에 다시 올 것이다 :)
Jacob Vlijm

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

야곱에게 대단히 감사합니다! 설정을 올바르게 했다고 생각 하지만 각 창이 전체 화면으로 열립니다. 어떤 아이디어?
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>
Ron Thompson

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와 함께 작동한다고 보장 할 수는 없지만 그 이유가 없습니다. 그것은 필요 wmctrl, xdpyinfodisper설치할 수 :

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> = 키 입력을 보내려는 창을 여는 명령. <지연> = 키 스트로크를 보내기 전에 밀리 초 단위의 대기 시간; <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

@Tim 아니오, 적어도 마지막 줄을 제거하지는 않습니다. 이것은 꽤 쓸모가 없다는 데 동의하지만 명령 내에서 다를 수있는 것은 괄호로 묶으면 더 잘 형식화됩니다. 이것은 언어 이론의 표준 표기법입니다 구문 범주 (편집을 참조)에 적용하고 명령 이름을 백틱으로 묶으면 즉시 형식화되어 (AB의 편집 참조) 더 나은 형식이라고 생각합니다. 이 모든 것이 내 머리 꼭대기에있는 것은 아니라는 점에 유의하십시오. 전에 의심을 품고 메타에 대해 질문 했습니다
kos

그래, 지금은 괜찮아 :) <>이 표준이며, 나는``어떤 명령 주위에서든 간다 :)
Tim

3

그래픽 사용자 인터페이스를 통해이 작업을 쉽게 수행 할 수있는 Unity 용 Worksets ( github ) 라는 응용 프로그램을 빌드했습니다 . 무료이며 오픈 소스입니다.

t 트레이 메뉴

기본적으로 여기에 답변으로 나열된 wmctrl 및 xdotool 솔루션의 래퍼이며 이러한 설정을 신속하게 만들고 저장하는 쉬운 방법을 제공합니다.


1

Jacob 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

나는 위에서 Terdon의 스크립트 를 가지고 놀고 새로운 것을 추가했습니다 (모니터를 선택하고 각 모니터의 높이를 설정할 수있는 기능). 내가 생각하는 더 많은 모니터를 추가 할 수 있습니다. 바라건대 다른 사람들이 유용하다고 생각합니다.

기본 구문 :

prog_name monitor l/r/m window_name (optional)

여기서 prog_name은이 코드를 저장 한 것입니다. 모니터는 모니터 번호입니다 (예 : 1 또는 2). l / r / m은 왼쪽 또는 오른쪽 또는 최대입니다. window_name은 대상 창의 이름 (또는 이름의 일부)입니다.

예 :

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.