1
0
mirror of https://github.com/gryf/moveto.git synced 2025-12-18 20:10:25 +01:00

Added py3 support

This commit is contained in:
2021-09-10 12:19:37 +02:00
parent b318abe5ba
commit 25d64e5430

150
moveto.py
View File

@@ -3,7 +3,7 @@
Position/place windows in WindowMaker. Position/place windows in WindowMaker.
Script calculates size of the target windows depending on current screen size. Script calculates size of the target windows depending on current screen size.
Required python 2.7 Required python 3.9
Dependencies: Dependencies:
- docopt - docopt
@@ -125,16 +125,16 @@ Date: 2015-12-13 Added simple detection of certain windows, which doesn't
Date: 2016-01-15 Moved corrections of the position of the QT apps after the Date: 2016-01-15 Moved corrections of the position of the QT apps after the
columns gets calculated columns gets calculated
Date: 2017-01-13 Removed pygtk dependency, don't rely on display names Date: 2017-01-13 Removed pygtk dependency, don't rely on display names
Version: 1.7 Date: 2021-09-10 removed docopt, added support for py3
""" """
from subprocess import Popen, PIPE, call, check_output import argparse
import logging import logging
import os import os
import re import re
import sys import subprocess
from docopt import docopt
__version__ = 1.8
# TODO: Make it configurable (lots of options starting from ini file) # TODO: Make it configurable (lots of options starting from ini file)
@@ -142,12 +142,12 @@ from docopt import docopt
def get_magic_number(): def get_magic_number():
"""Get the numbers for window shift and position""" """Get the numbers for window shift and position"""
out = Popen(['xdotool', 'getactivewindow'], res = subprocess.run(['xdotool', 'getactivewindow'], encoding='utf-8',
stdout=PIPE).communicate()[0] capture_output=True)
out = out.strip() out = res.stdout.strip()
out = Popen(['xwininfo', '-id', out], res = subprocess.run(['xwininfo', '-id', out], encoding='utf-8',
stdout=PIPE).communicate()[0] capture_output=True)
out.strip() out = res.stdout.strip()
for line in out.split("\n"): for line in out.split("\n"):
line = line.strip() line = line.strip()
if line.startswith("Relative upper-left Y"): if line.startswith("Relative upper-left Y"):
@@ -156,15 +156,16 @@ def get_magic_number():
return magic * 2 + 1, magic + 8 return magic * 2 + 1, magic + 8
MAGIC_NO, DECORATIONS_HEIGHT = get_magic_number() MAGIC_NO, DECORATIONS_HEIGHT = get_magic_number()
def get_window_name(): def get_window_name():
"""Return the current active window name""" """Return the current active window name"""
name = Popen(["xdotool", "getactivewindow", "getwindowname"], res = subprocess.run(["xdotool", "getactivewindow", "getwindowname"],
stdout=PIPE).communicate()[0] encoding='utf-8', capture_output=True)
name = name.strip() name = res.stdout.strip()
logging.debug('window name: %s', name) logging.debug('window name: %s', name)
return name return name
@@ -176,7 +177,7 @@ def get_monitors():
dimensions (as a tuple position x, y and dimension x and y) dimensions (as a tuple position x, y and dimension x and y)
""" """
connected = re.compile('^(?P<display_name>.+)\sconnected\s' connected = re.compile('^(?P<display_name>[a-zA-Z0-9-]+)\s[a-zA-Z\s]+\s'
'(?P<x>\d+)x' '(?P<x>\d+)x'
'(?P<y>\d+)\+' '(?P<y>\d+)\+'
'(?P<sx>\d+)\+' '(?P<sx>\d+)\+'
@@ -185,10 +186,12 @@ def get_monitors():
monitors = {} monitors = {}
randr = Popen(['xrandr'], stdout=PIPE) res = subprocess.run(['xrandr'], encoding='utf-8', capture_output=True)
out = check_output('grep connected'.split(), stdin=randr.stdout)
for line in res.stdout.split('\n'):
if 'disconnected' in line or 'connected' not in line:
continue
for line in out.split('\n'):
res = connected.match(line) res = connected.match(line)
if not res: if not res:
continue continue
@@ -383,10 +386,11 @@ class WMWindow(object):
arranged vertically. Note, that clip may or may not influence the arranged vertically. Note, that clip may or may not influence the
process, since it might be placed freely, and contains more dockapps process, since it might be placed freely, and contains more dockapps
or appicons than dock itself.""" or appicons than dock itself."""
res = Popen("xwininfo -tree -root -children".split(),
stdout=PIPE).communicate()[0] res = subprocess.run("xwininfo -tree -root -children".split(),
encoding='utf-8', capture_output=True)
result = {} result = {}
for item in res.split("\n"): for item in res.stdout.split("\n"):
if "64x64" not in item: if "64x64" not in item:
continue continue
@@ -423,9 +427,10 @@ class WMWindow(object):
""" """
self.x = self.y = self.pos_x = self.pos_y = None self.x = self.y = self.pos_x = self.pos_y = None
out = Popen(["xdotool", "getactivewindow", "getwindowgeometry"], res = subprocess.run(["xdotool", "getactivewindow",
stdout=PIPE).communicate()[0] "getwindowgeometry"],
out = out.strip().split("\n") encoding='utf-8', capture_output=True)
out = res.stdout.strip().split("\n")
if len(out) != 3: if len(out) != 3:
logging.warning('Cannot get window size and position for %s', logging.warning('Cannot get window size and position for %s',
@@ -554,12 +559,12 @@ class WMWindow(object):
return coord_map[which] return coord_map[which]
def cycle(monitors, right=False, main_screen=None): def cycle(monitors, args):
"""Cycle through the window states""" """Cycle through the window states"""
wmwin = WMWindow(monitors, main_screen) wmwin = WMWindow(monitors, args.monitor_name)
current_state = wmwin.guess_dimensions() current_state = wmwin.guess_dimensions()
direction = "right" if right else "left" direction = "right" if args.right else "left"
logging.debug('direction: %s, current_state %s', direction, current_state) logging.debug('direction: %s, current_state %s', direction, current_state)
if direction == "left": if direction == "left":
@@ -594,74 +599,85 @@ def cycle(monitors, right=False, main_screen=None):
'mousemove', str(coords['pos_x'] + coords['size_x'] / 2), 'mousemove', str(coords['pos_x'] + coords['size_x'] / 2),
str(coords['pos_y'] + coords['size_y'] / 2)] str(coords['pos_y'] + coords['size_y'] / 2)]
call(cmd) subprocess.run(cmd)
def show_monitors(monitors): def show_monitors(monitors, args):
"""Print out available monitors""" """Print out available monitors"""
print "Available monitors:" print("Available monitors:")
for name, data in monitors.items(): for name, data in monitors.items():
mon = data.copy() mon = data.copy()
mon.update({'name': name}) mon.update({'name': name})
logging.debug('%(name)s at %(sx)sx%(sy)s with dimensions ' print('%(name)s at %(sx)sx%(sy)s with dimensions %(x)sx%(y)s' % mon)
'%(x)sx%(y)s', mon)
def move_mouse(monitors, name): def move_mouse(monitors, args):
"""Move the mosue pointer to the left upper corner oft the specified by """Move the mosue pointer to the left upper corner oft the specified by
the name screen""" the name screen"""
mon = monitors.get(name) mon = monitors.get(args.monitor_name)
# if not mon: # if not mon:
# logging.warning('No such monitor: %s', name) # logging.warning('No such monitor: %s', name)
# return # return
posx = mon['sx'] + 15 posx = int(mon['sx']) + 15
posy = mon['sy'] + 50 posy = int(mon['sy']) + 50
cmd = ['xdotool', 'mousemove', str(posx), str(posy)] cmd = ['xdotool', 'mousemove', str(posx), str(posy)]
call(cmd) subprocess.run(cmd)
def main(): def main():
"""get the arguments, run the app""" """get the arguments, run the app"""
arguments = """Move windows around mimicking Windows7 flag+arrows behaviour parser = argparse.ArgumentParser(description="Move windows around "
"mimicking Windows7 flag+arrows "
"behaviour")
parser.add_argument('-v', '--version', help='Show version',
action='store_true')
Usage: subparsers = parser.add_subparsers(help='supported commands')
%(prog)s move (left|right) [-r|-l] [-m NAME] [-d]
%(prog)s mousemove -m NAME [-d]
%(prog)s showmonitors [-d]
%(prog)s (-h | --help)
%(prog)s --version
Options: move = subparsers.add_parser('move', help='Move window')
-m NAME --monitor-name=NAME Name of the monitor to be treated as the main group = move.add_mutually_exclusive_group()
one (so the one containing dock) group.add_argument('--left', action='store_true')
-r --dock-right Dock is on the right edge of the rightmost group.add_argument('--right', action='store_true')
screen group = move.add_mutually_exclusive_group()
-l --dock-left Dock is on the left edge of the leftmost screen group.add_argument('-r', '--dock-right', action='store_true',
-h --help Show this screen. help='Dock is on the right edge of the rightmost '
-v --version Show version. 'screen')
-d --debug Show debug messages. group.add_argument('-l', '--dock-left', action='store_true',
help='Dock is on the left edge of the leftmost screen')
move.add_argument('-m', '--monitor-name', help='Name of the monitor to be '
'treated as the main one (so the one containing dock)')
move.add_argument('-d', '--debug', action='store_true',
help='Show debug messages')
move.set_defaults(func=cycle)
""" % {'prog': sys.argv[0]} mousemove = subparsers.add_parser('mousemove', help='Move mouse pointer')
opts = docopt(arguments, version=1.7) mousemove.add_argument('-m', '--monitor-name', help='Name of the monitor '
level = logging.DEBUG if opts['--debug'] else logging.WARNING 'to move mouse pointer to', required=True)
mousemove.add_argument('-d', '--debug', action='store_true',
help='Show debug messages')
mousemove.set_defaults(func=move_mouse)
showmonitors = subparsers.add_parser('showmonitors')
showmonitors.add_argument('-d', '--debug', action='store_true',
help='Show debug messages')
showmonitors.set_defaults(func=show_monitors)
args = parser.parse_args()
if args.version:
print(__version__)
return
level = logging.DEBUG if args.debug else logging.WARNING
logging.basicConfig(filename=os.path.expanduser('~/moveto.log'), logging.basicConfig(filename=os.path.expanduser('~/moveto.log'),
format='%(funcName)s:%(lineno)d %(message)s', format='%(funcName)s:%(lineno)d %(message)s',
level=level) level=level)
monitors = get_monitors() monitors = get_monitors()
if opts['showmonitors']: args.func(monitors, args)
show_monitors(monitors)
return
if opts['mousemove']:
move_mouse(monitors, opts['--monitor-name'])
return
if opts['move']:
cycle(monitors, bool(opts['right']),
main_screen=opts['--monitor-name'])
if __name__ == '__main__': if __name__ == '__main__':