Commit da0ebacc authored by chrysn's avatar chrysn

Port to GTK3 and Python3, drop Metacity keybindings

This includes PEP8/pylint and general variable renaming.
parents 39274148 46f567b5
[flake8]
builtins=_
max-line-length = 120
ignore=E402,E266
.mypy_cache/
__pycache__/
This diff is collapsed.
#!/usr/bin/env python
#!/usr/bin/env python3
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
......
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Exceptions and generic classes"""
# pylint: disable=fixme
from math import pi
class FileLoadError(Exception): pass
class FileLoadError(Exception):
pass
class FileSyntaxError(FileLoadError):
"""A file's syntax could not be parsed."""
class InadequateConfiguration(Exception):
"""A configuration is incompatible with the current state of X."""
class BetterList(list):
"""List that can be split like a string"""
def indices(self, item):
i = -1
while True:
try:
i = self.index(item, i+1)
i = self.index(item, i + 1)
except ValueError:
break
yield i
......@@ -40,38 +48,41 @@ class BetterList(list):
def split(self, item):
indices = list(self.indices(item))
yield self[:indices[0]]
for x in (self[a+1:b] for (a,b) in zip(indices[:-1], indices[1:])):
for x in (self[a + 1:b] for (a, b) in zip(indices[:-1], indices[1:])):
yield x
yield self[indices[-1]+1:]
yield self[indices[-1] + 1:]
class Size(tuple):
"""2-tuple of width and height that can be created from a '<width>x<height>' string"""
def __new__(cls, arg):
if isinstance(arg, basestring):
if isinstance(arg, str):
arg = [int(x) for x in arg.split("x")]
arg = tuple(arg)
assert len(arg)==2
assert len(arg) == 2
return super(Size, cls).__new__(cls, arg)
width = property(lambda self:self[0])
height = property(lambda self:self[1])
width = property(lambda self: self[0])
height = property(lambda self: self[1])
def __str__(self):
return "%dx%d"%self
return "%dx%d" % self
class NamedSize(object):
class NamedSize:
"""Object that behaves like a size, but has an additional name attribute"""
def __init__(self, size, name):
self._size = size
self.name = name
width = property(lambda self:self[0])
height = property(lambda self:self[1])
width = property(lambda self: self[0])
height = property(lambda self: self[1])
def __str__(self):
if "%dx%d"%(self.width, self.height) in self.name:
if "%dx%d" % (self.width, self.height) in self.name:
return self.name
else:
return "%s (%dx%d)"%(self.name, self.width, self.height)
return "%s (%dx%d)" % (self.name, self.width, self.height)
def __iter__(self):
return self._size.__iter__()
......@@ -82,51 +93,58 @@ class NamedSize(object):
def __len__(self):
return 2
class Position(tuple):
"""2-tuple of left and top that can be created from a '<left>x<top>' string"""
def __new__(cls, arg):
if isinstance(arg, basestring):
if isinstance(arg, str):
arg = [int(x) for x in arg.split("x")]
arg = tuple(arg)
assert len(arg)==2
assert len(arg) == 2
return super(Position, cls).__new__(cls, arg)
left = property(lambda self:self[0])
top = property(lambda self:self[1])
left = property(lambda self: self[0])
top = property(lambda self: self[1])
def __str__(self):
return "%dx%d"%self
return "%dx%d" % self
class Geometry(tuple):
"""4-tuple of width, height, left and top that can be created from an XParseGeometry style string"""
# FIXME: use XParseGeometry instead of an own incomplete implementation
def __new__(cls, width, height=None, left=None, top=None):
if isinstance(width, basestring):
width,rest = width.split("x")
height,left,top = rest.split("+")
if isinstance(width, str):
width, rest = width.split("x")
height, left, top = rest.split("+")
return super(Geometry, cls).__new__(cls, (int(width), int(height), int(left), int(top)))
def __str__(self):
return "%dx%d+%d+%d"%self
return "%dx%d+%d+%d" % self
width = property(lambda self:self[0])
height = property(lambda self:self[1])
left = property(lambda self:self[2])
top = property(lambda self:self[3])
width = property(lambda self: self[0])
height = property(lambda self: self[1])
left = property(lambda self: self[2])
top = property(lambda self: self[3])
position = property(lambda self:Position(self[2:4]))
size = property(lambda self:Size(self[0:2]))
position = property(lambda self: Position(self[2:4]))
size = property(lambda self: Size(self[0:2]))
class Rotation(str):
"""String that represents a rotation by a multiple of 90 degree"""
def __init__(self, original_me):
if self not in ('left','right','normal','inverted'):
def __init__(self, _original_me):
super().__init__()
if self not in ('left', 'right', 'normal', 'inverted'):
raise Exception("No know rotation.")
is_odd = property(lambda self: self in ('left','right'))
_angles = {'left':pi/2,'inverted':pi,'right':3*pi/2,'normal':0}
is_odd = property(lambda self: self in ('left', 'right'))
_angles = {'left': pi / 2, 'inverted': pi, 'right': 3 * pi / 2, 'normal': 0}
angle = property(lambda self: Rotation._angles[self])
def __repr__(self):
return '<Rotation %s>'%self
return '<Rotation %s>' % self
LEFT = Rotation('left')
RIGHT = Rotation('right')
......
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
......@@ -18,27 +18,33 @@
Run by calling the main() function."""
import gtk
# pylint: disable=wrong-import-position
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from . import widget
def main():
w = gtk.Window()
w.connect('destroy',gtk.main_quit)
r = widget.ARandRWidget()
r.load_from_x()
b = gtk.Button("Reload")
b.connect('clicked', lambda *args: r.load_from_x())
b2 = gtk.Button("Apply")
b2.connect('clicked', lambda *args: r.save_to_x())
v = gtk.VBox()
w.add(v)
v.add(r)
v.add(b)
v.add(b2)
w.set_title('Simple ARandR Widget Demo')
w.show_all()
gtk.main()
window = Gtk.Window()
window.connect('destroy', Gtk.main_quit)
arandr = widget.ARandRWidget(window=window)
arandr.load_from_x()
reload_button = Gtk.Button("Reload")
reload_button.connect('clicked', lambda *args: arandr.load_from_x())
apply_button = Gtk.Button("Apply")
apply_button.connect('clicked', lambda *args: arandr.save_to_x())
vbox = Gtk.VBox()
window.add(vbox)
vbox.add(arandr)
vbox.add(reload_button)
vbox.add(apply_button)
window.set_title('Simple ARandR Widget Demo')
window.show_all()
Gtk.main()
This diff is collapsed.
""" This file is licensed under GPLv3, see https://www.gnu.org/licenses/ """
import gettext
TRANSLATION = gettext.translation('arandr', fallback=True)
def _(msg: str) -> str:
return TRANSLATION.gettext(msg)
def _n(singular: str, plural: str, count: int) -> str:
return TRANSLATION.ngettext(singular, plural, count)
......@@ -2,112 +2,114 @@
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import gettext
gettext.install('arandr')
# pylint: disable=missing-docstring
from .i18n import _
__version__ = '0.1.9'
PROGRAMNAME = _(u'ARandR Screen Layout Editor')
## translators, please translate in the style of "Another XRandR GUI
## (ein weiteres GUI für XRandR)" so users get both the explanation of
## the acronym and a localized version.
# translators, please translate in the style of "Another XRandR GUI
# (ein weiteres GUI für XRandR)" so users get both the explanation of
# the acronym and a localized version.
PROGRAMDESCRIPTION = _(u'Another XRandR GUI')
COPYRIGHT = u'© chrysn 2008 – 2016, Себастьян Gli ţa Κατινα 2011, Johannes Holmberg 2015'
COPYRIGHT = u'© chrysn 2008 – 2019, Себастьян Gli ţa Κατινα 2011, Johannes Holmberg 2015, actionless 2019'
# other names of contributors found in the git history. mailmap (see
# git-shortlog(1)) won't cut it, because some contributors don't have any email
# address at all (or might want to be attributed without address).
COMMITTER_ALIASES = {
'chrysn <chrysn@84c1553d-868a-485e-9ebb-c7de0e225ff1>': 'chrysn <chrysn@fsfe.org>',
'Rax <r-a-x@launchpad>': 'Rax Garfield',
'o-157 <Unknown>': 'o-157',
'cdemoulins <clement@archivel.fr>': 'Clément Démoulins <clement@archivel.fr>',
'sjb <gseba@users.sourceforge.net>': 'Себастьян Gli ţa Κατινα <gseba@users.sourceforge.net>',
'Chandru <gundachandru@gmail.com>': 'gundachandru <gundachandru@gmail.com>',
'Dimitris Giouroukis <digitalbckp@launchpad>': 'Dimitris Giouroukis',
'Alir3z4 <agahia.com@gmail.com>': 'Alireza Savand <agahia.com@gmail.com>',
'el_libre como el chaval <el.libre@gmail.com>': 'el_libre <el.libre@gmail.com>',
'phantomx <megaphantomx@bol.com.br>': 'Phantom X <megaphantomx@bol.com.br>',
}
'chrysn <chrysn@84c1553d-868a-485e-9ebb-c7de0e225ff1>': 'chrysn <chrysn@fsfe.org>',
'Rax <r-a-x@launchpad>': 'Rax Garfield',
'o-157 <Unknown>': 'o-157',
'cdemoulins <clement@archivel.fr>': 'Clément Démoulins <clement@archivel.fr>',
'sjb <gseba@users.sourceforge.net>': 'Себастьян Gli ţa Κατινα <gseba@users.sourceforge.net>',
'Chandru <gundachandru@gmail.com>': 'gundachandru <gundachandru@gmail.com>',
'Dimitris Giouroukis <digitalbckp@launchpad>': 'Dimitris Giouroukis',
'Alir3z4 <agahia.com@gmail.com>': 'Alireza Savand <agahia.com@gmail.com>',
'el_libre como el chaval <el.libre@gmail.com>': 'el_libre <el.libre@gmail.com>',
'phantomx <megaphantomx@bol.com.br>': 'Phantom X <megaphantomx@bol.com.br>',
}
TRANSLATORS_OVERRIDES = {
# fixing stuff all over the place
'chrysn <chrysn@fsfe.org>': ['de', 'en'],
'Michal Čihař <michal@cihar.com>': ['cs'],
# see 3b0b47b3665 / c1a7b7edad34
'Mohammad Alhargan <malham1@gmail.com>': ['ar'],
}
# fixing stuff all over the place
'chrysn <chrysn@fsfe.org>': ['de', 'en'],
'Michal Čihař <michal@cihar.com>': ['cs'],
# see 3b0b47b3665 / c1a7b7edad34
'Mohammad Alhargan <malham1@gmail.com>': ['ar'],
}
# everything below this line is updated semi-manually using `./setup.py update_translator_credits`
TRANSLATORS = [
'Algimantas Margevičius <margevicius.algimantas@gmail.com>',
'Alireza Savand <agahia.com@gmail.com>',
'Bakr Al-Tamimi <Bakr.Tamimi@gmail.com>',
'Balázs Úr <urbalazs@gmail.com>',
'Belvar <glasbarg@gmail.com>',
'Bruno_Patri <bruno.patri@gmail.com>',
'Carezero <carezero@qq.com>',
'ChuChangMing <82724824@qq.com>',
'Clément Démoulins <clement@archivel.fr>',
'Denis Jukni <deblenden8@gmail.com>',
'Dimitris Giouroukis',
'Efstathios Iosifidis <iefstathios@gmail.com>',
'Fred Maranhão <fred.maranhao@gmail.com>',
'Guilherme Souza Silva <g.szsilva@gmail.com>',
'HsH <hsh@runtu.org>',
'Igor <vmta@yahoo.com>',
'Ingemar Karlsson <ingemar@ingk.se>',
'Ivan Vantu5z <vantu5z@mail.ru>',
'Joe Hansen <joedalton2@yahoo.dk>',
'Kristjan Räts <kristjanrats@gmail.com>',
'Lu Ca <lmelonimamo@yahoo.it>',
'Luca Vetturi <io@lucavettu.com>',
'Luis García Sevillano <floss.dev@gmail.com>',
'Mantas Kriaučiūnas <mantas@akl.lt>',
'Mehmet Gülmen <memetgulmen@gmail.com>',
'Michal Čihař <michal@cihar.com>',
'Miguel Anxo Bouzada <mbouzada@gmail.com>',
'Mohammad Alhargan <malham1@gmail.com>',
'Olexandr Nesterenko <olexn@ukr.net>',
'ParkJS <HeavensBus@gmail.com>',
'Phantom X <megaphantomx@bol.com.br>',
'Piotr Strebski <strebski@o2.pl>',
'Quizzlo <paolone.marco@gmail.com>',
'Rax Garfield',
'Ricardo A. Hermosilla Carrillo <ra.hermosillac@gmail.com>',
'RooTer <rooter@kyberian.net>',
'Sebastian Wahl <swahl11@student.aau.dk>',
'Semsudin Abdic <abdic88@gmail.com>',
'Slavko <linux@slavino.sk>',
'Slobodan Simić <slsimic@gmail.com>',
'Tamás Nagy <kisagy@gmail.com>',
'Tuux <tuxa@galaxie.eu.org>',
'Vladimir <vladimir-csp@yandex.ru>',
'aboodilankaboot <shiningmoon25@gmail.com>',
'agilob <weblate@agilob.net>',
'cho bkwon <chobkwon@gmail.com>',
'chrysn <chrysn@fsfe.org>',
'el_libre <el.libre@gmail.com>',
'gundachandru <gundachandru@gmail.com>',
'ikmaak <info@ikmaak.nl>',
'josep constanti <jconstanti@yahoo.es>',
'o-157',
'pCsOrI <pcsori@gmail.com>',
'reza khan <reza_khn@yahoo.com>',
'wimfeijen <wimfeijen@gmail.com>',
'Себастьян Gli ţa Κατινα <gseba@users.sourceforge.net>'
]
'Algimantas Margevičius <margevicius.algimantas@gmail.com>',
'Alireza Savand <agahia.com@gmail.com>',
'Bakr Al-Tamimi <Bakr.Tamimi@gmail.com>',
'Balázs Úr <urbalazs@gmail.com>',
'Belvar <glasbarg@gmail.com>',
'Bruno_Patri <bruno.patri@gmail.com>',
'Carezero <carezero@qq.com>',
'ChuChangMing <82724824@qq.com>',
'Clément Démoulins <clement@archivel.fr>',
'Denis Jukni <deblenden8@gmail.com>',
'Dimitris Giouroukis',
'Efstathios Iosifidis <iefstathios@gmail.com>',
'Fred Maranhão <fred.maranhao@gmail.com>',
'Guilherme Souza Silva <g.szsilva@gmail.com>',
'HsH <hsh@runtu.org>',
'Igor <vmta@yahoo.com>',
'Ingemar Karlsson <ingemar@ingk.se>',
'Ivan Vantu5z <vantu5z@mail.ru>',
'Joe Hansen <joedalton2@yahoo.dk>',
'Kristjan Räts <kristjanrats@gmail.com>',
'Lu Ca <lmelonimamo@yahoo.it>',
'Luca Vetturi <io@lucavettu.com>',
'Luis García Sevillano <floss.dev@gmail.com>',
'Mantas Kriaučiūnas <mantas@akl.lt>',
'Mehmet Gülmen <memetgulmen@gmail.com>',
'Michal Čihař <michal@cihar.com>',
'Miguel Anxo Bouzada <mbouzada@gmail.com>',
'Mohammad Alhargan <malham1@gmail.com>',
'Olexandr Nesterenko <olexn@ukr.net>',
'ParkJS <HeavensBus@gmail.com>',
'Phantom X <megaphantomx@bol.com.br>',
'Piotr Strebski <strebski@o2.pl>',
'Quizzlo <paolone.marco@gmail.com>',
'Rax Garfield',
'Ricardo A. Hermosilla Carrillo <ra.hermosillac@gmail.com>',
'RooTer <rooter@kyberian.net>',
'Sebastian Wahl <swahl11@student.aau.dk>',
'Semsudin Abdic <abdic88@gmail.com>',
'Slavko <linux@slavino.sk>',
'Slobodan Simić <slsimic@gmail.com>',
'Tamás Nagy <kisagy@gmail.com>',
'Tuux <tuxa@galaxie.eu.org>',
'Vladimir <vladimir-csp@yandex.ru>',
'aboodilankaboot <shiningmoon25@gmail.com>',
'agilob <weblate@agilob.net>',
'cho bkwon <chobkwon@gmail.com>',
'chrysn <chrysn@fsfe.org>',
'el_libre <el.libre@gmail.com>',
'gundachandru <gundachandru@gmail.com>',
'ikmaak <info@ikmaak.nl>',
'josep constanti <jconstanti@yahoo.es>',
'o-157',
'pCsOrI <pcsori@gmail.com>',
'reza khan <reza_khn@yahoo.com>',
'wimfeijen <wimfeijen@gmail.com>',
'Себастьян Gli ţa Κατινα <gseba@users.sourceforge.net>'
]
This diff is collapsed.
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .auxiliary import Position
class Snap(object):
class Snap:
"""Snap-to-edges manager"""
def __init__(self, size, tolerance, list):
def __init__(self, size, tolerance, positions):
self.tolerance = tolerance
self.horizontal = set()
self.vertical = set()
for i in list:
for i in positions:
self.vertical.add(i[0].left)
self.vertical.add(i[0].left+i[1].width)
self.vertical.add(i[0].left + i[1].width)
self.horizontal.add(i[0].top)
self.horizontal.add(i[0].top+i[1].height)
self.horizontal.add(i[0].top + i[1].height)
self.vertical.add(i[0].left-size.width)
self.vertical.add(i[0].left+i[1].width-size.width)
self.horizontal.add(i[0].top-size.height)
self.horizontal.add(i[0].top+i[1].height-size.height)
self.vertical.add(i[0].left - size.width)
self.vertical.add(i[0].left + i[1].width - size.width)
self.horizontal.add(i[0].top - size.height)
self.horizontal.add(i[0].top + i[1].height - size.height)
self.vertical.add((i[0].left + i[1].width/2)-size.width/2)
self.horizontal.add((i[0].top + i[1].height/2)-size.height/2)
self.vertical.add((i[0].left + i[1].width / 2) - size.width / 2)
self.horizontal.add((i[0].top + i[1].height / 2) - size.height / 2)
def suggest(self, position):
vertical = [x for x in self.vertical if abs(x-position[0])<self.tolerance]
horizontal = [y for y in self.horizontal if abs(y-position[1])<self.tolerance]
vertical = [x for x in self.vertical if abs(
x - position[0]) < self.tolerance]
horizontal = [y for y in self.horizontal if abs(
y - position[1]) < self.tolerance]
if vertical:
position = Position((vertical[0], position[1]))
......
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/env python
#!/usr/bin/env python3
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
......@@ -134,11 +134,11 @@ class update_translator_credits(NoOptionCommand):
contributions.update(TRANSLATORS_OVERRIDES)
print "====================== for screenlayout/meta.py ================"
print
print "TRANSLATORS = [\n " + ",\n ".join("'%s'"%c for c in sorted(contributions)) + "\n ]"
print
print
print("====================== for screenlayout/meta.py ================")
print()
print("TRANSLATORS = [\n " + ",\n ".join("'%s'"%c for c in sorted(contributions)) + "\n ]")
print()
print()
by_language_set = {}
for name, languages in contributions.items():
......@@ -170,24 +170,24 @@ class update_translator_credits(NoOptionCommand):
else:
return lang
print "====================== for README ================"
print
print "\n".join(sorted("* %s (%s)"%(", ".join(strip_address(c) for c in sorted(contributors)), ", ".join(sorted(language2name(l).encode('utf8') for l in languages))) for (languages, contributors) in by_language_set.items()))
print
print("====================== for README ================")
print()
print("\n".join(sorted("* %s (%s)"%(", ".join(strip_address(c) for c in sorted(contributors)), ", ".join(sorted(language2name(l).encode('utf8') for l in languages))) for (languages, contributors) in by_language_set.items())))
print()
by_language = {}
for name, languages in contributions.items():
for l in languages:
by_language.setdefault(l, set()).add(name)
print "====================== for debian/copyright ================"
print
print("====================== for debian/copyright ================")
print()
for l, names in sorted(by_language.items()):
print "Files: data/po/%s.po"%l
print "Copyright: 2008-%s, chrysn <chrysn@fsfe.org>"%datetime.datetime.now().year
print("Files: data/po/%s.po"%l)
print("Copyright: 2008-%s, chrysn <chrysn@fsfe.org>"%datetime.datetime.now().year)
for n in sorted(names):
print " %s"%n
print "License: GPL-3+"
print
print(" %s"%n)
print("License: GPL-3+")
print()
class build(_build):
sub_commands = _build.sub_commands + [('build_trans', None), ('build_man', None)]
......
#!/usr/bin/env python
#!/usr/bin/env python3
# ARandR -- Another XRandR GUI
# Copyright (C) 2008 -- 2011 chrysn <chrysn@fsfe.org>
......@@ -28,4 +28,4 @@ p.parse_args()
current = screenlayout.xrandr.XRandR()
current.load_from_x()
print current.save_to_shellscript_string(["%(xrandr)s"]).strip()
print(current.save_to_shellscript_string(["%(xrandr)s"]).strip())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment