# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
"""
Notes:
# https://stackoverflow.com/questions/51070465/is-it-possible-to-get-the-directory-of-a-specific-nautilus-window-in-a-script?noredirect=1#comment95427874_51070465
sudo apt install python-nautilus
mkdir -p ~/.local/share/nautilus-python/extensions
TODO:
need to handle wayland.
To replace xdootool, look at
wtype,
river,
xmonad,
xmobar
dmenu,
xlock
"""
import time
import re
import logging
from vimtk import cplat
from shlex import quote as cmd_quote
logger = logging.getLogger(__name__)
[docs]
def is_directory_open(dpath):
# FIXME
import ubelt as ub # pip install me! https://github.com/Erotemic/ubelt
import platform
from os.path import basename
import re
computer_name = platform.node()
dname = basename(dpath)
if not ub.find_exe('wmctrl'):
raise Exception('wmctrl must be installed')
for line in ub.cmd('wmctrl -lxp')['out'].splitlines():
parts = re.split(' +', line)
if len(parts) > 3 and parts[3] == 'nautilus.Nautilus':
if parts[4] == computer_name:
# FIXME: Might be a False positive!
line_dname = ' '.join(parts[5:])
if line_dname == dname:
return True
# Always correctly returns False
return False
[docs]
def wmctrl_list():
import ubelt as ub
lines = ub.cmd('wmctrl -lxp')['out']
windows = {}
for line in lines.split('\n'):
if line:
parts = re.split(' +', line)
hexid, deskid, pid, wm_class, client = parts[0:5]
title = ' '.join(parts[5:])
wm_id = int(hexid, 16)
windows[wm_id] = {
'hexid': hexid,
'wm_id': wm_id,
'deskid': deskid,
'pid': int(pid),
'wm_class': wm_class,
'client': client,
'title': title,
}
return windows
[docs]
def windows_in_order():
"""
CommandLine:
python -m vimtk.xctrl windows_in_order
References:
https://stackoverflow.com/questions/15638885/linux-how-to-get-a-list-of-all-visible-windows
Example:
>>> # xdoctest: +REQUIRES(env:DISPLAY)
>>> from vimtk.xctrl import *
>>> result = list(windows_in_order())
>>> for win in result:
... if win.visible():
... print(win)
Ignore:
# Why is this slow somtimes?
import subprocess
subprocess.call(['xprop', '-root'])
proc = subprocess.Popen(['xprop', '-root'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1, text=True)
out, err = proc.communicate()
proc = subprocess.Popen('xprop -root', shell=True, stdout=subprocess.PIPE, bufsize=1)
info = ub.cmd('xprop -root | grep "^_NET_CLIENT_LIST_STACKING"', shell=True)
info = ub.cmd('xprop -root _NET_CLIENT_LIST_STACKING', shell=True)
info = ub.cmd('xprop -root _NET_CLIENT_LIST_STACKING')
# I don't understand why this can be fast sometimes and slow others
import subprocess
import timerit
import itertools as it
import ubelt as ub
options = {
'bufsize': [-1, 0],
'shell': [True, False],
'stdout': [subprocess.PIPE, None],
'stderr': [subprocess.PIPE, None],
'stdin': [subprocess.PIPE, None],
'universal_newlines': [True, False],
# 'cwd': [None, '.']
# 'env': [None, {}]
}
ti = timerit.Timerit(3, bestof=1, verbose=3)
for vals in it.product(*options.values()):
opt = ub.dzip(options.keys(), vals)
command = ['xprop', '-root', '_NET_CLIENT_LIST_STACKING']
name = ub.urepr(opt, explicit=True, nobr=1, nl=0, itemsep='')
if opt['shell']:
command = ' '.join(command)
for timer in ti.reset(name):
with timer:
proc = subprocess.Popen(command, **opt)
out, err = proc.communicate()
assert proc.returncode == 0
# print(out)
for timer in ti.reset('ubelt'):
with timer:
print(ub.cmd('xprop -root _NET_CLIENT_LIST_STACKING')['out'])
print(ub.urepr(ub.sorted_vals(ti.measures['mean']), nl=1, precision=6))
proc = subprocess.Popen('xprop -root', shell=True, stdout=subprocess.PIPE, bufsize=0)
out, err = proc.communicate()
info = ub.cmd('xprop -root', verbose=3, shell=True)
ub.cmd('wmctrl -lxp')['out']
os.system('wmctrl -lxp')
"""
# info = XCtrl.cmd('xprop -root')
info = XCtrl.cmd('xprop -root _NET_CLIENT_LIST_STACKING')
lines = [line for line in info['out'].split('\n')
if line.startswith('_NET_CLIENT_LIST_STACKING')]
assert len(lines) == 1, str(lines)
winid_order_str = lines[0]
winid_order = winid_order_str.split('#')[1].strip().split(', ')[::-1]
winid_order = [int(h, 16) for h in winid_order]
windows = wmctrl_list()
for wm_id in winid_order:
info = windows[wm_id]
yield XWindow(wm_id, info)
[docs]
def find_windows(proc=None, title=None, visible=True):
"""
CommandLine:
python -m vimtk.xctrl find_windows
Example:
>>> # xdoctest: +REQUIRES(env:DISPLAY)
>>> from vimtk.xctrl import * # NOQA
>>> for win in find_windows('gvim'):
>>> print(ub.urepr(win.info()))
>>> for win in find_windows('terminator'):
>>> print(ub.urepr(win.info()))
"""
import re
for win in windows_in_order():
flag = True
if proc:
try:
proc_name = win.process_name()
flag &= bool(re.match(proc, proc_name))
except Exception:
flag = False
if title:
try:
win_title = win.title()
flag &= bool(re.match(title, win_title))
except Exception:
flag = False
if visible:
try:
flag &= win.visible()
except Exception:
flag = False
if flag:
yield win
[docs]
class XWindow(object):
"""
TODO: make API consistent with the win32 version
"""
def __init__(self, wm_id, info=None, sleeptime=0.01):
self.wm_id = wm_id
self.cache = info
self.sleeptime = 0.01
[docs]
@classmethod
def find(XWindow, pattern, method='mru'):
wm_id = XCtrl.find_window_id(pattern, method=method)
self = XWindow(wm_id)
return self
[docs]
@classmethod
def findall(XWindow, pattern):
wm_ids = XCtrl.findall_window_ids(pattern)
result = [XWindow(wm_id) for wm_id in wm_ids]
return result
[docs]
@classmethod
def current(XWindow):
r"""
CommandLine:
VIMTK_TEST=1 xdoctest -m vimtk.xctrl XWindow.current
Example:
>>> # xdoctest: +REQUIRES(env:VIMTK_TEST)
>>> from vimtk.xctrl import * # NOQA
>>> import ubelt as ub
>>> self = XWindow.current()
>>> print('self: XWindow = {}'.format(ub.urepr(self, nl=1)))
>>> print('info = ' + ub.urepr(self.wininfo()))
"""
import ubelt as ub
wm_id = int(ub.cmd('xdotool getwindowfocus')['out'].strip())
win = XWindow(wm_id)
return win
[docs]
def _wmquery(self, key):
if self.cache:
return self.cache[key]
windows = wmctrl_list()
info = windows[self.wm_id]
self.cache = info
return info['title']
@property
def hexid(self):
return hex(self.wm_id)
[docs]
def title(self):
self._wmquery('title')
[docs]
def visible(self):
""" Basically true for wmctrl (afaik) """
return True
def __nice__(self):
try:
fname = self.process_name()
except Exception:
fname = '<error: unable to get process name>'
return str(self.wm_id) + ' ' + fname + ' ' + repr(self.title())
[docs]
def wm_class(self):
return self._wmquery('wm_class')
[docs]
def process(self):
import psutil
pid = self._wmquery('pid')
proc = psutil.Process(pid)
return proc
[docs]
def size(self):
# Get the current size
info = self.wininfo()
w, h = int(info['Width']), int(info['Height'])
dsize = (w, h)
return dsize
[docs]
def resize(self, width, height):
"""
CommandLine:
VIMTK_TEST=1 xdoctest -m vimtk.xctrl XWindow.resize
Example:
>>> # xdoctest: +REQUIRES(env:VIMTK_TEST)
>>> from vimtk.xctrl import * # NOQA
>>> self = XWindow.current()
>>> w, h = self.size()
>>> self.resize(w + 10, h + 10)
"""
import ubelt as ub
command = f'xdotool windowsize {self.wm_id} {width} {height}'
ub.cmd(command, verbose=3)
[docs]
def wininfo(self):
"""
"""
import ubelt as ub
cmdinfo = ub.cmd('xwininfo -id {}'.format(self.wm_id))
if cmdinfo['ret'] != 0:
print('info = {}'.format(ub.urepr(cmdinfo, nl=1)))
raise Exception(cmdinfo['ret'])
out = cmdinfo['out']
info = {}
curr_key = None
val_accum = []
# Parse key/val lines
def accept(info, curr_key, val_accum):
if curr_key is not None:
info[curr_key] = (' '.join(val_accum)).strip()
val_accum.clear()
for line in out.split('\n'):
if ':' in line:
accept(info, curr_key, val_accum)
key, val = line.split(':', 1)
val_accum.append(val)
curr_key = key.strip()
else:
val_accum.append(line)
accept(info, curr_key, val_accum)
return info
[docs]
def process_name(self):
proc = self.process()
return proc.name()
[docs]
def focus(self, sleeptime=None):
import ubelt as ub
ub.cmd('wmctrl -ia {}'.format(self.hexid))
time.sleep(sleeptime if sleeptime is not None else self.sleeptime)
[docs]
def info(self):
info = self.cache.copy() # type: ignore
info['proc_name'] = self.process_name()
return info
[docs]
def move(self, bbox):
"""
CommandLine:
# List windows
wmctrl -l
# List desktops
wmctrl -d
# Window info
xwininfo -id 60817412
python -m vimtk.xctrl XWindow.move joncrall 0+1920,680,400,600,400
python -m vimtk.xctrl XWindow.move joncrall [0,0,1000,1000]
python -m vimtk.xctrl XWindow.move GVIM special2
python -m vimtk.xctrl XWindow.move joncrall special2
python -m vimtk.xctrl XWindow.move x-terminal-emulator.X-terminal-emulator [0,0,1000,1000]
CommandLine:
python -m vimtk.xctrl XWindow.move
CommandLine:
python -m vimtk.xctrl XCtrl.move_window
Example:
>>> # xdoctest: +SKIP
>>> XCtrl.move_window('joncrall', '[0,0,1000,1000]')
Ignore:
# >>> orig_window = []
# >>> X = xctrl.XCtrl
win_key = 'x-terminal-emulator.X-terminal-emulator'
win_id = X.findall_window_ids(key)[0]
python -m xctrl XCtrl.findall_window_ids gvim
"""
monitor_infos = {
i + 1: cplat.get_resolution_info(i)
for i in range(2)
}
# TODO: cut out borders
# TODO: fix screeninfo monitor offsets
# TODO: dynamic num screens
def rel_to_abs_bbox(m, x, y, w, h):
""" monitor_num, relative x, y, w, h """
minfo = monitor_infos[m]
# print('minfo(%d) = %s' % (m, ub.urepr(minfo),))
mx, my = minfo['off_x'], minfo['off_y']
mw, mh = minfo['pixels_w'], minfo['pixels_h']
# Transform to the absolution position
abs_x = (x * mw) + mx
abs_y = (y * mh) + my
abs_w = (w * mw)
abs_h = (h * mh)
abs_bbox = [abs_x, abs_y, abs_w, abs_h]
abs_bbox = ','.join(map(str, map(int, abs_bbox)))
return abs_bbox
if self.title().startswith('joncrall') and bbox == 'special2':
# Specify the relative position
abs_bbox = rel_to_abs_bbox(m=2,
x=0.0, y=0.7,
w=1.0, h=0.3)
elif self.title().startswith('GVIM') and bbox == 'special2':
# Specify the relative position
abs_bbox = rel_to_abs_bbox(m=2,
x=0.0, y=0.0,
w=1.0, h=0.7)
else:
abs_bbox = ','.join(map(str, eval(bbox)))
print('MOVING: win_key = %r' % (self.title(),))
print('TO: abs_bbox = %r' % (abs_bbox,))
# abs_bbox.replace('[', '').replace(']', '')
# get = lambda cmd: XCtrl.cmd(' '.join(["/bin/bash", "-c", cmd]))['out'] # NOQA
win_id = XCtrl.find_window_id(self.title(), error='raise')
print('MOVING: win_id = %r' % (win_id,))
fmtdict = locals()
cmd_list = [
("wmctrl -ir {win_id} -b remove,maximized_horz".format(**fmtdict)),
("wmctrl -ir {win_id} -b remove,maximized_vert".format(**fmtdict)),
("wmctrl -ir {win_id} -e 0,{abs_bbox}".format(**fmtdict)),
]
print('\n'.join(cmd_list))
for cmd in cmd_list:
XCtrl.cmd(cmd)
[docs]
def _wmctrl_terminal_patterns():
"""
wmctrl patterns associated with common terminals
"""
terminal_pattern = r'|'.join([
'terminal',
re.escape('terminator.Terminator'), # gtk3 terminator
re.escape('x-terminal-emulator.X-terminal-emulator'), # gtk2 terminator
# other common terminal applications
'tilix',
'konsole',
'rxvt',
'terminology',
'xterm',
'tilda',
'Yakuake',
'kitty.kitty',
])
return terminal_pattern
[docs]
class XCtrl(object):
r"""
xdotool key ctrl+shift+i
References:
http://superuser.com/questions/382616/detecting-currently-active-window
http://askubuntu.com/questions/455762/xbindkeys-wont-work-properly
Ignore:
xdotool keyup --window 0 7 type --clearmodifiers ---window 0 '%paste'
# List current windows:
wmctrl -l
# Get current window
xdotool getwindowfocus getwindowname
#====
# Get last opened window
#====
win_title=x-terminal-emulator.X-terminal-emulator
key_ = 'x-terminal-emulator.X-terminal-emulator'
# Get all windows in current workspace
workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1`
win_list=`wmctrl -lx | grep $win_title | grep " $workspace_number " | awk '{print $1}'`
# Get stacking order of windows in current workspace
win_order=$(xprop -root|grep "^_NET_CLIENT_LIST_STACKING" | tr "," " ")
echo $win_order
CommandLine:
python -m vimtk.xctrl XCtrl:0
Example:
>>> # xdoctest: +SKIP
>>> # Script
>>> orig_window = []
>>> copy_text_to_clipboard(lorium_ipsum())
>>> doscript = [
>>> ('focus', 'x-terminal-emulator.X-terminal-emulator'),
>>> ('type', '%paste'),
>>> ('key', 'KP_Enter'),
>>> # ('focus', 'GVIM')
>>> ]
>>> XCtrl.do(*doscript, sleeptime=.01)
Ignore:
>>> # xdoctest: +SKIP
>>> copy_text_to_clipboard(text)
>>> if '\n' in text or len(text) > 20:
>>> text = '\'%paste\''
>>> else:
>>> text = cmd_quote(text.lstrip(' '))
>>> ('focus', 'GVIM'),
>>> #
>>> doscript = [
>>> ('focus', 'x-terminal-emulator.X-terminal-emulator'),
>>> ('type', text),
>>> ('key', 'KP_Enter'),
>>> ]
>>> XCtrl.do(*doscript, sleeptime=.01)
"""
# @staticmethod
# def send_raw_key_input(keys):
# print('send key input: %r' % (keys,))
# args = ['xdotool', 'type', keys]
# XCtrl.cmd(*args, quiet=True, silence=True)
[docs]
@classmethod
def cmd(XCtrl, command):
import ubelt as ub
logging.debug('[cmd] {}'.format(command))
info = ub.cmd(command)
if info['ret'] != 0:
logging.warning('Something went wrong {}'.format(ub.urepr(info))) # type: ignore
return info
[docs]
@classmethod
def findall_window_ids(XCtrl, pattern=None):
"""
Returns:
List[int]: wmctl ids for the matching windows
CommandLine:
python -m vimtk.xctrl XCtrl.findall_window_ids --pat=gvim --noskip
python -m vimtk.xctrl XCtrl.findall_window_ids --pat=gvim
python -m vimtk.xctrl XCtrl.findall_window_ids --pat=joncrall
Example:
>>> # xdoctest: +REQUIRES(--noskip)
>>> from vimtk.xctrl import * # NOQA
>>> pattern = ub.argval('--pat')
>>> winid_list = XCtrl.findall_window_ids(pattern)
>>> print('winid_list = {!r}'.format(winid_list))
Ignore:
wmctrl -l
xprop -id
wmctrl -l | awk '{print $1}' | xprop -id
0x00a00007 | grep "WM_CLASS(STRING)"
"""
# List all windows and their identifiers
info = XCtrl.cmd('wmctrl -lx')
lines = info['out'].split('\n')
if pattern is not None:
# Find windows with identifiers matching the pattern
lines = [line for line in lines if re.search(pattern, line)]
# Get the hex-id portion of the output
winid_list = [line.split()[0] for line in lines]
winid_list = [int(h, 16) for h in winid_list if h]
return winid_list
[docs]
@classmethod
def sort_window_ids(XCtrl, winid_list, order='mru'):
"""
Orders window ids by most recently used
"""
def isect(list1, list2):
set2 = set(list2)
return [item for item in list1 if item in set2]
winid_order = XCtrl.sorted_window_ids(order)
sorted_win_ids = isect(winid_order, winid_list)
return sorted_win_ids
[docs]
@staticmethod
def killold(pattern, num=4):
"""
Leaves no more than `num` instances of a program alive. Ordering is
determined by most recent usage.
CommandLine:
python -m vimtk.xctrl XCtrl.killold gvim 2
Example:
>>> # xdoctest: +SKIP
>>> XCtrl = xctrl.XCtrl
>>> pattern = 'gvim'
>>> num = 2
"""
import psutil
import ubelt as ub
num = int(num)
winid_list = XCtrl.findall_window_ids(pattern)
winid_list = XCtrl.sort_window_ids(winid_list, 'mru')[num:]
info = XCtrl.cmd('wmctrl -lxp')
lines = info['out'].split('\n')
lines = [' '.join(list(ub.take(line.split(), [0, 2]))) # type: ignore
for line in lines]
output_lines = lines
# output_lines = XCtrl.cmd(
# """wmctrl -lxp | awk '{print $1 " " $3}'""",
# **cmdkw)['out'].strip().split('\n')
output_fields = [line.split(' ') for line in output_lines]
output_fields = [(int(wid, 16), int(pid)) for wid, pid in output_fields]
pid_list = [pid for wid, pid in output_fields if wid in winid_list]
for pid in pid_list:
proc = psutil.Process(pid=pid)
proc.kill()
[docs]
@staticmethod
def sorted_window_ids(order='mru'):
"""
Returns window ids orderd by criteria
default is mru (most recently used)
CommandLine:
xprop -root | grep "^_NET_CLIENT_LIST_STACKING" | tr "," " "
python -m vimtk.xctrl XCtrl.sorted_window_ids
CommandLine:
python -m vimtk.xctrl XCtrl.sorted_window_ids
Example:
>>> # xdoctest: +SKIP
>>> winid_order = XCtrl.sorted_window_ids()
>>> print('winid_order = {!r}'.format(winid_order))
"""
info = XCtrl.cmd('xprop -root')
lines = [line for line in info['out'].split('\n')
if line.startswith('_NET_CLIENT_LIST_STACKING')]
assert len(lines) == 1, str(lines)
winid_order_str = lines[0]
winid_order = winid_order_str.split('#')[1].strip().split(', ')[::-1]
winid_order = [int(h, 16) for h in winid_order]
if order == 'lru':
winid_order = winid_order[::-1]
elif order == 'mru':
winid_order = winid_order
else:
raise NotImplementedError(order)
return winid_order
[docs]
@staticmethod
def find_window_id(pattern, method='mru', error='raise'):
"""
xprop -id 0x00a00007 | grep "WM_CLASS(STRING)"
"""
logging.debug('Find window id pattern={}, method={}'.format(pattern, method))
winid_candidates = XCtrl.findall_window_ids(pattern)
if len(winid_candidates) == 0:
if error == 'raise':
available_windows = XCtrl.cmd('wmctrl -lx')['out']
msg = 'No window matches pattern=%r' % (pattern,)
msg += '\navailable windows are:\n%s' % (available_windows,)
logger.error(msg)
raise Exception(msg)
win_id = None
elif len(winid_candidates) == 1:
win_id = winid_candidates[0]
else:
# print('Multiple (%d) windows matches pattern=%r' % (
# len(winid_list), pattern,))
# Find most recently used window with the focus name.
win_id = XCtrl.sort_window_ids(winid_candidates, method)[0]
return win_id
[docs]
@staticmethod
def current_gvim_edit(op='e', fpath=''):
r"""
CommandLine:
python -m vimtk.xctrl XCtrl.current_gvim_edit sp ~/.bashrc
"""
import ubelt as ub
import pathlib
assert fpath is not None
fpath = ub.shrinkuser(pathlib.Path(fpath).resolve()) # type: ignore
# print('fpath = %r' % (fpath,))
cplat.copy_text_to_clipboard(fpath)
doscript = [
('focus', 'gvim'),
('key', 'Escape'),
('type2', ';' + op + ' ' + fpath),
# ('type2', ';' + op + ' '),
# ('key', 'ctrl+v'),
('key', 'KP_Enter'),
]
XCtrl.do(*doscript, verbose=0, sleeptime=.001)
[docs]
@staticmethod
def copy_gvim_to_terminal_script(text, return_to_win="1", verbose=0, sleeptime=.02):
"""
vimtk.xctrl.XCtrl.copy_gvim_to_terminal_script('print("hi")', verbose=1)
python -m vimtk.xctrl XCtrl.copy_gvim_to_terminal_script "echo hi" 1 1
If this doesn't work make sure pyperclip is installed and set to xsel
print('foobar')
echo hi
"""
# Prepare to send text to xdotool
cplat.copy_text_to_clipboard(text)
if verbose:
print('text = %r' % (text,))
print(cplat.get_clipboard())
terminal_pattern = r'\|'.join([
'terminal',
re.escape('terminator.Terminator'), # gtk3 terminator
re.escape('x-terminal-emulator.X-terminal-emulator'), # gtk2 terminator
])
# Build xdtool script
doscript = [
('remember_window_id', 'ACTIVE_WIN'),
# ('focus', 'x-terminal-emulator.X-terminal-emulator'),
('focus', terminal_pattern),
('key', 'ctrl+shift+v'),
('key', 'KP_Enter'),
]
if '\n' in text:
# Press enter twice for multiline texts
doscript += [
('key', 'KP_Enter'),
]
if return_to_win == "1":
doscript += [
('focus_id', '$ACTIVE_WIN'),
]
# execute script
# verbose = 1
XCtrl.do(*doscript, sleeptime=sleeptime, verbose=verbose)
[docs]
@staticmethod
def do(*cmd_list, **kwargs):
"""
DEPRICATE THIS
"""
import ubelt as ub
verbose = kwargs.get('verbose', False)
if verbose:
print = logger.info
else:
print = logger.debug
print('Executing x do: %s' % (ub.urepr(cmd_list),)) # type: ignore
# http://askubuntu.com/questions/455762/xbindkeys-wont-work-properly
# Make things work even if other keys are pressed
defaultsleep = 0.0
sleeptime = kwargs.get('sleeptime', defaultsleep)
time.sleep(.05)
XCtrl.cmd('xset r off')
memory = {}
for count, item in enumerate(cmd_list):
# print('item = %r' % (item,))
sleeptime = kwargs.get('sleeptime', defaultsleep)
assert isinstance(item, tuple)
assert len(item) >= 2
xcmd, key_ = item[0:2]
if len(item) >= 3:
if isinstance(item[2], str) and item[2].endswith('?'):
sleeptime = float(item[2][:-1])
print('special command sleep')
print('sleeptime = %r' % (sleeptime,))
else:
sleeptime = float(item[2])
args = []
print('# Step %d' % (count,))
print('xcmd = {!r}'.format(xcmd))
if xcmd == 'focus':
key_ = str(key_)
if key_.startswith('$'):
key_ = memory[key_[1:]]
pattern = key_
win_id = XCtrl.find_window_id(pattern, method='mru')
if win_id is None:
args = ['wmctrl', '-xa', pattern]
else:
args = ['wmctrl', '-ia', hex(win_id)]
elif xcmd == 'focus_id':
key_ = str(key_)
if key_.startswith('$'):
key_ = memory[key_[1:]]
assert isinstance(key_, str)
args = ['wmctrl', '-ia', hex(key_)] # type: ignore
elif xcmd == 'remember_window_id':
memory[key_] = XCtrl.current_window_id()
continue
elif xcmd == 'remember_window_name':
memory[key_] = XCtrl.current_window_name()
continue
elif xcmd == 'type':
args = [
'xdotool',
'keyup', '--window', '0', '7',
'type', '--clearmodifiers',
'--window', '0', str(key_)
]
elif xcmd == 'type2':
args = [
'xdotool', 'type', cmd_quote(str(key_))
]
elif xcmd == 'xset-r-on':
args = ['xset', 'r', 'on']
elif xcmd == 'xset-r-off':
args = ['xset', 'r', 'off']
else:
args = ['xdotool', str(xcmd), str(key_)]
print('args = {!r}'.format(args))
XCtrl.cmd(args)
if sleeptime > 0:
time.sleep(sleeptime)
XCtrl.cmd('xset r on')
[docs]
@staticmethod
def current_window_id():
logging.debug('Get current window id')
info = XCtrl.cmd('xdotool getwindowfocus')
value = int(info['out'].strip())
logging.debug('... current window id = {}'.format(value))
return value
[docs]
@staticmethod
def current_window_name():
logging.debug('Get current window name')
info = XCtrl.cmd('xdotool getwindowfocus getwindowname')
value = cmd_quote(info['out'].strip())
logging.debug('... current window name = {}'.format(value))
return value
[docs]
@staticmethod
def focus_window(winhandle, path=None, name=None, sleeptime=.01):
"""
sudo apt-get install xautomation
apt-get install autokey-gtk
wmctrl -xa gnome-terminal.Gnome-terminal
wmctrl -xl
"""
print('focus: ' + winhandle)
args = ['wmctrl', '-xa', winhandle]
XCtrl.cmd(args)
time.sleep(sleeptime)
[docs]
@classmethod
def send_keys(XCtrl, key, sleeptime=0.1):
args = ['xdotool', 'key', str(key)]
XCtrl.cmd(args)
time.sleep(sleeptime)
# @classmethod
# def focus(XCtrl, pattern=None, win_id=None, sleeptime=.01):
# """
# sudo apt-get install xautomation
# apt-get install autokey-gtk
# wmctrl -xa gnome-terminal.Gnome-terminal
# wmctrl -xl
# """
# if pattern is not None:
# assert win_id is None
# if win_id is None:
# assert pattern is not None
# win_id = XCtrl.find_window_id(pattern, method='mru')
# if win_id is None:
# args = ['wmctrl', '-xa', pattern]
# else:
# args = ['wmctrl', '-ia', hex(win_id)]
# XCtrl.cmd(*args, verbose=False)
# time.sleep(sleeptime)
if __name__ == '__main__':
r"""
CommandLine:
export PYTHONPATH=$PYTHONPATH:$HOME/code/vimtk
python -m vimtk.xctrl
"""
import xdoctest
xdoctest.doctest_module(__file__)