シェルスクリプトバージョン

シェルスクリプトバージョン

1 つのアクションに、そのアクションが配置されているワークスペースに応じて 2 つの異なる効果を持たせる方法があるかどうか知りたいです。

たとえば、ワークスペース 1 の場合は、Empathy のチャット リストにフォーカスするコマンドが使用されますが、ワークスペース 2 の場合は、Chrome を開くコマンドが使用されます。

これは、Compiz で画面の右端にマウスを移動することにリンクされます。

これは可能ですか?

答え1

見てxdotool. は、get_desktop現在表示されているデスクトップを出力します。

Ubuntu with Unity の場合、ワークスペースは と呼ばれviewports、左上隅の x 位置と y 位置の座標形式で表示されます。

例えば、

$ xdotool get_desktop_viewport     
4780 0

その情報を使用して、現在どのワークスペースにいるのかを把握し、各ワークスペースごとにコマンドを実行できます。

答え2

注記: 回答はパフォーマンス向上のためPythonで書き直されましたが、GUI要素は削除されています。セクションを参照してください。Python バージョン

シェルスクリプトバージョン

導入

以下のスクリプトを使用すると、現在アクティブなワークスペースに応じて特定のコマンドを実行できます。これはキーボード ショートカットにバインドされることを目的としています。スクリプトの動作のデモは、こちらでご覧いただけます: https://www.youtube.com/watch?v=oxim3JbeiVM

スクリプトの入手

この投稿からスクリプト ソースをコピーするか、次の手順に従ってインストールします。

  1. sudo apt-get install git
  2. cd /opt ; sudo git clone https://github.com/SergKolo/sergrep.git
  3. sudo chmod -R +x sergrep

ファイルは/opt/sergrep/unity_viewport_commands.sh

使用方法とオプションの概要

スクリプトには次のフラグがあります。

  • -r現在のビューポートに対してコマンドを実行する
  • -g新しいコマンドリストを生成する
  • -hヘルプテキストを印刷する
  • -v現在の設定を表示
  • -s単一のビューポートの設定を変更する

スクリプトは、特定のフラグを持つキーボード ショートカットにバインドされるように設計されています。たとえば、 コマンドを呼び出すには、Ctrl+ Alt+ がI バインドされます。unity_viewport_commands.sh -r

スクリプトをショートカットにバインドするには、.sh ファイルをキーボードの組み合わせにバインドするにはどうすればよいですか?

スクリプトソース

#!/usr/bin/env bash
#
###########################################################
# Author: Serg Kolo , contact: [email protected] 
# Date: April 18th, 2016
# Purpose: Script that runs a command depending
#          on the current viewport
# Written for: https://askubuntu.com/q/56367/295286
# Tested on: Ubuntu 14.04 , Unity 7.2.6
###########################################################
# Copyright: Serg Kolo , 2016
#    
#     Permission to use, copy, modify, and distribute this software is hereby granted
#     without fee, provided that  the copyright notice above and this permission statement
#     appear in all copies.
#
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
#     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#     DEALINGS IN THE SOFTWARE.

ARGV0="$0"
ARGC=$#
get_screen_geometry()
{
 xwininfo -root | awk '/-geometry/{gsub(/+|x/," ");print $2,$3}'  
}

gui_dialog()
{
  SCHEMA="org.compiz.core:/org/compiz/profiles/unity/plugins/core/"
  read swidth sdepth  <<< "$(get_screen_geometry)" 
  vwidth=$(gsettings get $SCHEMA hsize)
  vheight=$(gsettings get $SCHEMA vsize)
  
 width=0
 for horizontal in $(seq 1 $vwidth); do
    height=0 
    for vertical in $(seq 1 $vheight);  do

      # array+=( FALSE  )
      viewport+=( $(echo "$width"x"$height") )

    height=$(($height+$sdepth))
    done
 width=$(($width+$swidth))
 done

  local fmtstr=""
  for i in ${viewport[@]} ; do
    fmtstr=$fmtstr"$(printf "%s\"%s\" " "--add-entry=" $i)"
  done

  STR=$(zenity --forms --title="Set Viewport Commands" \
           --text='Please avoid using # character' --separator="#" \
           $fmtstr 2>/dev/null) 

  OLDIFS=$IFS
  IFS="#"
  commands=( $STR   )
  IFS=$OLDIFS
 
# for loop done with while loop
  counter=0
  while [ $counter -lt ${#viewport[@]}   ] ;
  do 
    echo "${viewport[$counter]}":"${commands[$counter]}"
    counter=$(($counter+1))
  done
}

get_current_viewport()
{
  xprop -root -notype _NET_DESKTOP_VIEWPORT  | \
      awk -F'=' '{gsub(/\,/,"x");gsub(/\ /,"");print $2}'
}

run_viewport_command()
{
  [ -r "$HOME"/"$DATAFILE"  ] || \
      { printf ">>> ERR: commands file doesn't exit. \
        \nCreate new one using -g flag" > /dev/stderr ; exit 1 ;}
  local VP=$(get_current_viewport)
  cmd=$(awk -v regex="^$VP" -F ':' '$0~regex{ $1="";print }' "$HOME"/"$DATAFILE")
  eval $cmd " &> /dev/null  &"
}


view_current_settings()
{
  if [ -r "$HOME"/"$DATAFILE"   ]; then
     cat "$HOME"/"$DATAFILE"  | \
     zenity --list --height=250 --width=250  \
     --title="current settings"  --column=""  2> /dev/null
  else
      printf ">>> ERR: commands file doesn't exist
      \\nCreate new one using -g flag" > /dev/stderr
      exit 1
  fi

}
 
change_single()
{
  if [ -r "$HOME"/"$DATAFILE"  ] ;then
    NEWLINE="$(zenity --forms --separator='#' \
         --add-entry="viewport to change(XPOSxYPOS):"\
         --add-entry="new command")"
    remove_this=$(awk -F '#' '{ print $1  }' <<< "$NEWLINE")
    sed -i '/^'$remove_this'/d' "$HOME"/"$DATAFILE"
    new_cmd=$(awk -F '#' '{$1="";printf "%s",$0}' <<< "$NEWLINE")
    echo "$remove_this":"$new_cmd" >> "$HOME"/"$DATAFILE"
  fi
}

print_usage()
{
cat << EOF

Usage: viewport_commands.sh [option] 
Copyright Serg Kolo , 2016

-r run a command for current viewport
-g generate new list of commands
-h print this text
-v view current settings
-s change setting for a single viewport

EOF
}



parse_args()
{
  [ $# -eq 0  ] && print_usage && exit 0
  local option OPTIND
  while getopts "grvhs" option ;
  do
     case ${option} in
        g) gui_dialog > "$HOME"/"$DATAFILE"
        ;;
        r) run_viewport_command 
        ;;
        v) view_current_settings
        ;;
        s) change_single
        ;;
        h) print_usage && exit 0
        ;;
        \?) echo "Invalid option: -$OPTARG" >&2
        ;;
     esac
  done
  shift $((OPTIND-1))

}

main()
{
  local DATAFILE=".viewport_commands"
  parse_args "$@"
  exit 0
}

main "$@"

シンプルなシェルスクリプトバージョン(元の回答)

Ubuntu はワークスペースの代わりにビューポートを使用します。これは、下と右に正の数でカウントされる座標系で、0,0左上のワークスペースがこれに該当します。

これを知っておくと、現在の座標を取得し、それをテストし、適切なコマンドを実行する簡単なスクリプトを作成できます。以下のスクリプトはそれを実行します。

#!/bin/bash
  
get_viewport()
{
  xprop -root -notype _NET_DESKTOP_VIEWPORT  | \
      awk -F '=' '{ gsub(/\ /,"");print $2 }'
}

get_viewport

case "$(get_viewport)" in 

   "0,0") notify-send 'You are in the top left viewport'
            ;;
   "2732,768") notify-send 'You are in the bottom right viewport'
            ;;

esac

notify-sendコマンドを任意のアクションに置き換えます。nohup COMMAND 2>/dev/null & コマンドがスクリプトをハングするのを避けるために使用します (notify-sendは例外なので、ここでは追加しませんでした)。

を使用してxprop -root -notype _NET_DESKTOP_VIEWPORT、各ビューポートの座標を決定します。

最後に、case ステートメント オプションにはスペースを入れないでください (例: "0,0"works but "0, 0"will not)。


Python バージョン

導入

このバージョンのスクリプトは同じ機能を実行しますが、シンプルさと使いやすさのためにコマンドライン引数やGUI要素は含まれていません。スクリプトは次の場所で入手できます。Github ギスト下記も同様です:

使用法:

使い方はとても簡単です:

python3 /path/to/workspace_command.py

スクリプトは現在のワークスペースを決定し、 で定義された適切なコマンドを実行します~/.workspace_commands.json。このファイルを最初に作成してください。そうしないとスクリプトは動作しません。また、各ワークスペースを定義するには二重引用符を使用し、コマンド + 引数を使用する必要があります。

サンプル~/workspace_commands.json

{
  "1":["nautilus"],
  "2":["firefox","google.com"],
  "3":["virtualbox"]
}

スクリプトのソースコード

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Author: Serg Kolo , contact: [email protected] 
Date: August 9th, 2016
Purpose: Spawns a command depending on current
         viewport, as defined in ~/.workspace_commands.json
Written for: https://askubuntu.com/q/56367/295286
Tested on: Ubuntu 16.04 LTS , Unity desktop


The MIT License (MIT)

Copyright © 2016 Sergiy Kolodyazhnyy <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
"""


# Just in case the user runs 
# the script with python 2, import
# print function
from __future__ import print_function
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gio,Gdk
import json
import subprocess
import os

def gsettings_get(schema,path,key):
    """Get value of gsettings schema"""
    if path is None:
        gsettings = Gio.Settings.new(schema)
    else:
        gsettings = Gio.Settings.new_with_path(schema,path)
    return gsettings.get_value(key)

def run_cmd(cmdlist):
    """ Reusable function for running shell commands"""
    try:
        stdout = subprocess.check_output(cmdlist)
    except subprocess.CalledProcessError:
        print(">>> subprocess:",cmdlist)
        sys.exit(1)
    else:
        if stdout:
            return stdout

def enumerate_viewports():
    """ generates enumerated dictionary of viewports and their
        indexes, counting left to right """
    schema="org.compiz.core"
    path="/org/compiz/profiles/unity/plugins/core/"
    keys=['hsize','vsize']
    screen = Gdk.Screen.get_default()
    screen_size=[ screen.get_width(),screen.get_height()]
    grid=[ int(str(gsettings_get(schema,path,key))) for key in keys]
    x_vals=[ screen_size[0]*x for x in range(0,grid[0]) ]
    y_vals=[screen_size[1]*x for x in range(0,grid[1]) ]
    
    viewports=[(x,y)  for y in y_vals for x in x_vals ]
    
    return {vp:ix for ix,vp in enumerate(viewports,1)}

def get_current_viewport():
    """returns tuple representing current viewport, 
       in format (width,height)"""
    vp_string = run_cmd(['xprop', '-root', 
                         '-notype', '_NET_DESKTOP_VIEWPORT'])
    vp_list=vp_string.decode().strip().split('=')[1].split(',')
    return tuple( int(i)  for i in vp_list )

def read_config_file():
    """ reads ~/.workspace_commands file """
    rcfile = os.path.join( os.path.expanduser('~'), 
                           '.workspace_commands.json')
    try:
        with open(rcfile) as config_file:
            config_data = json.load(config_file)
    except IOError as error:
        print(error.__repr__())
    else:
        if config_data:
            return config_data


def main():
   # get all the info we need first
   viewports_dict=enumerate_viewports()
   current_viewport = get_current_viewport()
   current_vp_number = viewports_dict[current_viewport]
   viewport_config = read_config_file()

   for vp,command in viewport_config.items():
       if int(vp) == current_vp_number:
          # spawn the command and let us exit
          pid = subprocess.Popen(command).pid
          break
   
if __name__ == '__main__':
    main()

マウスオーバーアクション:

元の質問では、画面の右側でマウスオーバーアクションを実行する方法について尋ねています。キーボードショートカットにリンクされている上記のスクリプトを使用することをお勧めしますが、マウスオーバーアクションも可能です。以下は、マウスが画面の右上隅にある場合に上記の Python バージョンを起動する簡単なスクリプトです。必要に応じてスクリプトを自由に調整してください。

#!/usr/bin/env python3
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gio,Gdk
import subprocess
from time import  sleep
def main():
    screen = Gdk.Screen.get_default()
    root_window = screen.get_root_window()

    while True:
        if root_window.get_pointer()[2] == 0 and \
           root_window.get_pointer()[1] >= root_window.get_width()-2:
               proc = subprocess.Popen(['python3','/home/user/bin/python/workspace_command.py']).pid
        sleep(0.75)

if __name__ == '__main__':
    main()

ノート:

同様のマウス イベント スクリプトは、コマンドを使用してその出力を解析するシェル スクリプトで実行できますxdotool getmouselocation。次のようなものになります。

$ xdotool getmouselocation
x:1140 y:420 screen:0 window:14680095

関連情報