1
0
mirror of https://github.com/gryf/moveto.git synced 2025-12-17 11:30:21 +01:00

Use gdk to dedect screen layout

This commit is contained in:
2015-01-05 13:33:08 +01:00
parent b5a2e1a431
commit 20684f77db

View File

@@ -6,7 +6,7 @@ Script calculates size of the target windows depending on current screen size.
Required python 2.7 Required python 2.7
Dependencies: Dependencies:
- xrandr - pygtk
- wmctrl - wmctrl
- xdotool - xdotool
- xwininfo - xwininfo
@@ -47,17 +47,20 @@ possible moves of the depicted window would be:
- move to screen 1 to the left half - move to screen 1 to the left half
- move to screen 1 to the right half - move to screen 1 to the right half
TODO: Make it more flexible with different window configurations
Author: Roman 'gryf' Dobosz <gryf73@gmail.com> Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
Date: 2013-01-06 Date: 2013-01-06
Version: 1.1 Date: 2014-03-31 (used pygtk instead of xrandr, which is faster)
Version: 1.2
""" """
import os
import sys import sys
import re import re
from subprocess import Popen, PIPE, call from subprocess import Popen, PIPE, call
import json
CACHE_FILENAME = "~/.cache/res_pos_win.cache" from gtk import gdk
DOCK_ON_RIGHT = True DOCK_ON_RIGHT = True
COVER_MINIWINDOWS = False COVER_MINIWINDOWS = False
COVER_DOCK = False COVER_DOCK = False
@@ -72,25 +75,12 @@ class Screens(object):
"""Class container for a Screen objects and whole area coordinates""" """Class container for a Screen objects and whole area coordinates"""
self.screens = [] self.screens = []
self.coords = () self.coords = ()
self.dimension = None
def append(self, screen): def append(self, screen):
"""Add screen""" """Add screen"""
self.screens.append(screen) self.screens.append(screen)
def dump(self):
"""Dump object as dictionary - suitable for serialziation"""
return {"coords": self.coords,
"screens": [scr.dump() for scr in self.screens]}
def load(self, data):
"""Recreate object state from provided dictionary"""
self.screens = []
self.coords = tuple(data["coords"])
for scr in data['screens']:
screen = Screen()
screen.load(scr)
self.screens.append(screen)
def guess_dimensions(self, window): def guess_dimensions(self, window):
""" """
Check wheter current window is in one of three states: maximized, Check wheter current window is in one of three states: maximized,
@@ -111,6 +101,7 @@ class Screens(object):
return None return None
class Screen(object): class Screen(object):
""" """
Holds separate display information. It can be separate X screen or just a Holds separate display information. It can be separate X screen or just a
@@ -150,7 +141,6 @@ class Screen(object):
# it is rare, but hell, shit happens # it is rare, but hell, shit happens
sx = sx - 1 sx = sx - 1
if self.main and not COVER_DOCK: if self.main and not COVER_DOCK:
# dock on the right side + 2px for border # dock on the right side + 2px for border
self.x = sx = sx - (64 + 2) self.x = sx = sx - (64 + 2)
@@ -169,31 +159,6 @@ class Screen(object):
self.maximized['size_y'] = self.right_half['size_y'] = \ self.maximized['size_y'] = self.right_half['size_y'] = \
self.left_half['size_y'] = sy - DECOTATORS_HEIGHT self.left_half['size_y'] = sy - DECOTATORS_HEIGHT
def dump(self):
"""
Return current Screen object state as dictionary suitable for
serialization
"""
return {"main": self.main,
"x": self.x,
"y": self.y,
"x_shift": self.x_shift,
"y_shift": self.y_shift,
"left_half": self.left_half,
"right_half": self.right_half,
"maximized": self.maximized}
def load(self, data):
"""Restore Screen state from provided dictionary"""
self.x = data['x']
self.y = data['y']
self.x_shift = data['x_shift']
self.y_shift = data['y_shift']
self.left_half = data['left_half']
self.right_half = data['right_half']
self.maximized = data['maximized']
self.main = data['main']
class WMWindow(object): class WMWindow(object):
""" """
@@ -201,7 +166,7 @@ class WMWindow(object):
surrounded environment (screens and such). surrounded environment (screens and such).
""" """
screen_re = re.compile("[^,]*,\scurrent\s(\d+)\sx\s(\d+),.*") screen_re = re.compile("[^,].*,\scurrent\s(\d+)\sx\s(\d+),.*")
device_re = re.compile(".*\sconnected\s(\d+)x(\d+)\+(\d+)\+(\d+)") device_re = re.compile(".*\sconnected\s(\d+)x(\d+)\+(\d+)\+(\d+)")
display_re = re.compile("^.*,\scurrent\s(\d+)\sx\s(\d+),\s.*$") display_re = re.compile("^.*,\scurrent\s(\d+)\sx\s(\d+),\s.*$")
position_re = re.compile("^\s+Position:\s(\d+),(\d+)\s.*$") position_re = re.compile("^\s+Position:\s(\d+),(\d+)\s.*$")
@@ -220,22 +185,9 @@ class WMWindow(object):
self.current_screen = 0 self.current_screen = 0
self.state = None self.state = None
self._load_screens() self._discover_screens()
self._get_props() self._get_props()
def _load_screens(self):
"""
Load screen form cache file or create them from scratch if cache
doesn't exists
"""
fname = os.path.expanduser(CACHE_FILENAME)
if not os.path.exists(fname):
self._discover_screens()
else:
with open(fname) as fp_:
self.screens = Screens()
self.screens.load(json.load(fp_))
def _get_props(self): def _get_props(self):
""" """
Update current window dimensions and position Update current window dimensions and position
@@ -281,45 +233,20 @@ class WMWindow(object):
def _discover_screens(self): def _discover_screens(self):
"""Create list of available screens. Assuming, that first screen """Create list of available screens. Assuming, that first screen
reported is main screen.""" reported is main screen."""
out = Popen(['xrandr'], stdout=PIPE).communicate()[0]
self.screens = Screens() self.screens = Screens()
for line in out.split("\n"): # get the screen dimension - it may be composed by several outputs
if self.device_re.match(line): self.display_size = (gdk.screen_width(), gdk.screen_height())
x, y, sx, sy = self.device_re.match(line).groups()
screen = Screen(x, y, sx, sy)
if not self.screens.screens:
screen.main = True
screen.calculate_columns()
self.screens.append(screen)
match = self.display_re.match(line)
if match:
self.display_size = match.groups()
fname = os.path.expanduser(CACHE_FILENAME) gdk_screen = gdk.screen_get_default()
for out_num in range(gdk_screen.get_n_monitors()):
# sort screens depending on the position (only horizontal order is sx, sy, x, y = gdk_screen.get_monitor_geometry(out_num)
# supported) screen = Screen(x, y, sx, sy)
screens = {} if not self.screens.screens:
screen.main = True
for screen in self.screens.screens: screen.calculate_columns()
screens[screen.x_shift] = screen self.screens.append(screen)
self.screens.screens = [screens[key] for key in
sorted(screens.keys())]
if not os.path.exists(fname):
try:
os.makedirs(os.path.dirname(fname))
except OSError:
pass
try:
with open(fname, "w") as fp:
json.dump(self.screens.dump(), fp)
except (OSError, IOError) as msg:
print "Error in creating cache file:\n", msg
def get_data(self): def get_data(self):
"""Return current window coordinates and size""" """Return current window coordinates and size"""
@@ -350,30 +277,27 @@ class WMWindow(object):
self.current_screen = idx self.current_screen = idx
return True return True
def full(self): # def left(self, screen_direction=None):
"""Maximize window""" # """Maximize to left half"""
def left(self, screen_direction=None): # coords = self.screens.screens[self.current_screen].left_half
"""Maximize to left half""" # cmd = ['xdotool', "getactivewindow",
# "windowmove", str(coords['pos_x']), str(coords['pos_y']),
# "windowsize", str(coords['size_x']), str(coords['size_y'])]
# call(cmd)
coords = self.screens.screens[self.current_screen].left_half # def right(self, screen_direction=None):
cmd = ['xdotool', "getactivewindow", # """Maximize to right half"""
"windowmove", str(coords['pos_x']), str(coords['pos_y']), # cmd = ['xdotool', "getactivewindow"]
"windowsize", str(coords['size_x']), str(coords['size_y'])] # if screen_direction:
call(cmd) # if not self.move_to_screen(screen_direction):
# return
def right(self, screen_direction=None): # if screen_direction:
"""Maximize to right half""" # move = self.move_to_screen(screen_direction)
cmd = ['xdotool', "getactivewindow"] # if not move:
if screen_direction: # return
if not self.move_to_screen(screen_direction): # cmd.extend(move)
return
if screen_direction:
move = self.move_to_screen(screen_direction)
if not move:
return
cmd.extend(move)
def get_coords(self, which): def get_coords(self, which):
"""Return screen coordinates""" """Return screen coordinates"""
@@ -422,6 +346,7 @@ def usage():
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 2: if len(sys.argv) < 2:
usage() usage()
sys.exit(1)
if sys.argv[1] == "cycle_left": if sys.argv[1] == "cycle_left":
cycle("left") cycle("left")
@@ -429,4 +354,4 @@ if __name__ == "__main__":
cycle("right") cycle("right")
else: else:
usage() usage()
sys.exit(1)