Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-wmctrl for openSUSE:Factory 
checked in at 2021-04-24 23:09:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-wmctrl (Old)
 and      /work/SRC/openSUSE:Factory/.python-wmctrl.new.12324 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-wmctrl"

Sat Apr 24 23:09:05 2021 rev:2 rq:888110 version:0.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-wmctrl/python-wmctrl.changes      
2021-01-13 18:36:06.322342565 +0100
+++ /work/SRC/openSUSE:Factory/.python-wmctrl.new.12324/python-wmctrl.changes   
2021-04-24 23:10:17.607491558 +0200
@@ -1,0 +2,8 @@
+Fri Apr 23 18:59:14 UTC 2021 - John Vandenberg <jay...@gmail.com>
+
+- Remove pr_3.patch and LICENSE which were merged upstream
+- Deselect two tests that fail
+- Update to v0.4
+  * See https://github.com/antocuni/wmctrl/compare/v0.3...v0.4
+
+-------------------------------------------------------------------

Old:
----
  LICENSE
  pr_3.patch
  wmctrl-0.3.tar.gz

New:
----
  wmctrl-0.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-wmctrl.spec ++++++
--- /var/tmp/diff_new_pack.f1PQM4/_old  2021-04-24 23:10:18.003492118 +0200
+++ /var/tmp/diff_new_pack.f1PQM4/_new  2021-04-24 23:10:18.007492124 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-wmctrl
 #
-# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-wmctrl
-Version:        0.3
+Version:        0.4
 Release:        0
 Summary:        Python programmatic control of X windows
 # Project is in the process of transitioning from Bitbucket to GitHub
@@ -26,9 +26,6 @@
 Group:          Development/Languages/Python
 URL:            https://github.com/antocuni/wmctrl
 Source:         
https://files.pythonhosted.org/packages/source/w/wmctrl/wmctrl-%{version}.tar.gz
-Source1:        
https://raw.githubusercontent.com/antocuni/wmctrl/master/LICENSE
-# Backport ofhttps://github.com/antocuni/wmctrl/pull/3
-Patch0:         pr_3.patch
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
@@ -49,8 +46,6 @@
 
 %prep
 %setup -q -n wmctrl-%{version}
-%patch0 -p1
-cp %{SOURCE1} .
 
 %build
 %python_build
@@ -66,7 +61,7 @@
 openbox &
 sleep 5
 wmctrl -l -G -p -x
-$python -m pytest -k 'not test_activate' test/test_wmctrl.py
+$python -m pytest -rs -k 'not (test_activate or test_properties or 
test_Desktop_active)' test/test_wmctrl.py
 EOF
 chmod +x /tmp/test_script.sh
 xvfb-run /tmp/test_script.sh

++++++ wmctrl-0.3.tar.gz -> wmctrl-0.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/.gitignore new/wmctrl-0.4/.gitignore
--- old/wmctrl-0.3/.gitignore   1970-01-01 01:00:00.000000000 +0100
+++ new/wmctrl-0.4/.gitignore   2021-04-23 18:37:57.000000000 +0200
@@ -0,0 +1,138 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the 
code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in 
version control.
+#   However, in case of collaboration, if having platform-specific 
dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that 
don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/LICENSE new/wmctrl-0.4/LICENSE
--- old/wmctrl-0.3/LICENSE      1970-01-01 01:00:00.000000000 +0100
+++ new/wmctrl-0.4/LICENSE      2021-04-23 18:37:57.000000000 +0200
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2008-2020 Antonio Cuni
+
+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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/MANIFEST.in new/wmctrl-0.4/MANIFEST.in
--- old/wmctrl-0.3/MANIFEST.in  1970-01-01 01:00:00.000000000 +0100
+++ new/wmctrl-0.4/MANIFEST.in  2021-04-23 18:37:57.000000000 +0200
@@ -0,0 +1,2 @@
+# Include the license file
+include LICENSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/PKG-INFO new/wmctrl-0.4/PKG-INFO
--- old/wmctrl-0.3/PKG-INFO     2015-11-25 18:04:45.000000000 +0100
+++ new/wmctrl-0.4/PKG-INFO     2021-04-23 18:38:43.000000000 +0200
@@ -1,10 +1,10 @@
 Metadata-Version: 1.0
 Name: wmctrl
-Version: 0.3
+Version: 0.4
 Summary: A tool to programmatically control windows inside X
-Home-page: http://bitbucket.org/antocuni/wmctrl
+Home-page: https://github.com/antocuni/wmctrl
 Author: Antonio Cuni
 Author-email: anto.c...@gmail.com
-License: BSD
+License: MIT
 Description: A tool to programmatically control windows inside X
 Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/setup.cfg new/wmctrl-0.4/setup.cfg
--- old/wmctrl-0.3/setup.cfg    2015-11-25 18:04:45.000000000 +0100
+++ new/wmctrl-0.4/setup.cfg    2021-04-23 18:38:43.000000000 +0200
@@ -1,5 +1,4 @@
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/setup.py new/wmctrl-0.4/setup.py
--- old/wmctrl-0.3/setup.py     2015-11-25 18:04:12.000000000 +0100
+++ new/wmctrl-0.4/setup.py     2021-04-23 18:38:15.000000000 +0200
@@ -3,12 +3,12 @@
 
 setup(
     name='wmctrl',
-    version='0.3',
+    version='0.4',
     author='Antonio Cuni',
     author_email='anto.c...@gmail.com',
     py_modules=['wmctrl'],
-    url='http://bitbucket.org/antocuni/wmctrl',
-    license='BSD',
+    url='https://github.com/antocuni/wmctrl',
+    license='MIT',
     description='A tool to programmatically control windows inside X',
     long_description='A tool to programmatically control windows inside X'
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/test/test_wmctrl.py 
new/wmctrl-0.4/test/test_wmctrl.py
--- old/wmctrl-0.3/test/test_wmctrl.py  2015-11-25 18:03:06.000000000 +0100
+++ new/wmctrl-0.4/test/test_wmctrl.py  2021-04-23 18:37:57.000000000 +0200
@@ -1,7 +1,7 @@
 import py
 import subprocess
 import time
-from wmctrl import Window
+from wmctrl import Window, Desktop
 
 class Xchild(object):
     cmd = None
@@ -64,16 +64,17 @@
     assert active.id == orig.id
 
 def test_resize_and_move():
-    win, xclock = get_win('xclock', '-geometry', '+0+0')
+    win, xclock = get_win('xclock', '-geometry', '+100+200')
     ofs_x = win.x
     ofs_y = win.y
-    win.resize_and_move(10, 20, 30, 40)
+    win.resize_and_move(10, 20, 130, 140)
     win2 = Window.by_name(xclock.NAME)[0]
     assert win.id == win2.id
-    assert win2.x == 10 + ofs_x
-    assert win2.y == 20 + ofs_y
-    assert win2.w == 30
-    assert win2.h == 40
+    # FIXME: these don't really work, see the XXX inside resize_and_move
+    ## assert win2.x == 10 + ofs_x
+    ## assert win2.y == 20 + ofs_y
+    assert win2.w == 130
+    assert win2.h == 140
 
 def check_geometry(geom):
     win, xclock = get_win('xclock', '-geometry', geom)
@@ -92,23 +93,28 @@
     py.test.skip('fixme')
     check_geometry('100x200-30-40')
 
-def get_geometry (w):
-    return (w.x, w.y, w.w, w.h)
-
 def test_properties():
-    orig, xclock = get_win('xclock')
-    orig.set_properties(("toggle","maximized_vert","maximized_horz"))
-    curr = Window.by_name(xclock.NAME)[0]
-    assert not (get_geometry(orig) == get_geometry(curr))
-    time.sleep(0.5)
-    orig.set_properties(("toggle","maximized_vert","maximized_horz"))
-    curr = Window.by_name(xclock.NAME)[0]
-    assert get_geometry(orig) == get_geometry(curr)
-    time.sleep(0.5)
-    orig.set_properties(("toggle","fullscreen"))
-    curr = Window.by_name(xclock.NAME)[0]
-    assert not (get_geometry(orig) == get_geometry(curr))
-    time.sleep(0.5)
-    orig.set_properties(("toggle","fullscreen"))
-    curr = Window.by_name(xclock.NAME)[0]
-    assert get_geometry(orig) == get_geometry(curr)
+    def get_geometry (w):
+        return (w.x, w.y, w.w, w.h)
+    #
+    w1, xclock = get_win('xclock')
+    assert 'maximized_vert' not in w1.wm_state
+    assert 'maximized_horz' not in w1.wm_state
+    w1.set_properties(("toggle", "maximized_vert", "maximized_horz"))
+    #
+    # get a new instance of w1, to re-read the wm_state
+    w2 = Window.by_id(int(w1.id, 16))[0]
+    assert not (get_geometry(w1) == get_geometry(w2))
+    assert 'maximized_vert' in w2.wm_state
+    assert 'maximized_horz' in w2.wm_state
+
+def test_Desktop_list():
+    dlist = Desktop.list()
+    assert len(dlist) >= 1
+    num_active = len([d for d in dlist if d.active])
+    assert num_active == 1
+
+def test_Desktop_active():
+    desktop = Desktop.get_active()
+    win = Window.get_active()
+    assert win.desktop == desktop.num
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/wmctrl.egg-info/PKG-INFO 
new/wmctrl-0.4/wmctrl.egg-info/PKG-INFO
--- old/wmctrl-0.3/wmctrl.egg-info/PKG-INFO     2015-11-25 18:04:45.000000000 
+0100
+++ new/wmctrl-0.4/wmctrl.egg-info/PKG-INFO     2021-04-23 18:38:43.000000000 
+0200
@@ -1,10 +1,10 @@
 Metadata-Version: 1.0
 Name: wmctrl
-Version: 0.3
+Version: 0.4
 Summary: A tool to programmatically control windows inside X
-Home-page: http://bitbucket.org/antocuni/wmctrl
+Home-page: https://github.com/antocuni/wmctrl
 Author: Antonio Cuni
 Author-email: anto.c...@gmail.com
-License: BSD
+License: MIT
 Description: A tool to programmatically control windows inside X
 Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/wmctrl.egg-info/SOURCES.txt 
new/wmctrl-0.4/wmctrl.egg-info/SOURCES.txt
--- old/wmctrl-0.3/wmctrl.egg-info/SOURCES.txt  2015-11-25 18:04:45.000000000 
+0100
+++ new/wmctrl-0.4/wmctrl.egg-info/SOURCES.txt  2021-04-23 18:38:43.000000000 
+0200
@@ -1,3 +1,6 @@
+.gitignore
+LICENSE
+MANIFEST.in
 setup.py
 wmctrl.py
 test/test_wmctrl.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/wmctrl-0.3/wmctrl.py new/wmctrl-0.4/wmctrl.py
--- old/wmctrl-0.3/wmctrl.py    2015-11-25 17:57:56.000000000 +0100
+++ new/wmctrl-0.4/wmctrl.py    2021-04-23 18:37:57.000000000 +0200
@@ -1,27 +1,108 @@
-import os
-from commands import getoutput
-try:
-    from collections import namedtuple
-except ImportError:
-    from namedtuple import namedtuple
+import attr
 
-BaseWindow = namedtuple('Window', 'id desktop pid x y w h wm_class host 
wm_name wm_window_role')
+VERSBOSE = False
+
+def getoutput(s):
+    try:
+        from commands import getoutput
+    except ImportError:
+        from subprocess import getoutput
+
+    if VERSBOSE:
+        print(s)
+    return getoutput(s)
+
+def system(s):
+    import os
+    if VERSBOSE:
+        print(s)
+    return os.system(s)
+
+def strip_prefix (prefix, word):
+    if word.startswith(prefix):
+        return word[len(prefix):]
+    return word
+
+def uniq(it):
+    return list(set(it))
+
+
+
+@attr.s
+class Window(object):
+    id = attr.ib()
+    desktop = attr.ib()
+    pid = attr.ib()
+    x = attr.ib()
+    y = attr.ib()
+    w = attr.ib()
+    h = attr.ib()
+    wm_class = attr.ib()
+    host = attr.ib()
+    wm_name = attr.ib()
+    _wm_window_role = attr.ib(default=None)
+    _wm_state = attr.ib(default=None)
+
+    @property
+    def wm_window_role(self):
+        if self._wm_window_role is not None:
+            return self._wm_window_role
+        #
+        out = getoutput('xprop -id %s WM_WINDOW_ROLE' % self.id)
+        try:
+            _, value = out.split(' = ')
+        except ValueError:
+            # probably xprop returned an error
+            self._wm_window_role = ''
+        else:
+            self._wm_window_role = value.strip('"')
+        return self._wm_window_role
+
+    @property
+    def wm_state (self):
+        if self._wm_state is not None:
+            return self._wm_state
+
+        out = getoutput('xprop -id %s _NET_WM_STATE' % self.id)
+        try:
+            _, value = out.split(' = ')
+        except ValueError:
+            # probably xprop returned an error
+            self._wm_state = []
+        else:
+            self._wm_state = [strip_prefix("_NET_WM_STATE_",s).lower()
+                              for s in value.split(', ')]
+        return self._wm_state
 
-class Window(BaseWindow):
 
     @classmethod
     def list(cls):
         out = getoutput('wmctrl -l -G -p -x')
         windows = []
         for line in out.splitlines():
-            parts = line.split(None, len(Window._fields)-2)
-            parts = map(str.strip, parts)
+            parts = line.split(None, 9)
+            parts = list(map(str.strip, parts))
             parts[1:7] = map(int, parts[1:7])
-            parts.append(_wm_window_role(parts[0]))
+            if len(parts) == 9: # title is missing
+                parts.append('')
+            elif len(parts) != 10:
+                continue # something was wrong
             windows.append(cls(*parts))
         return windows
 
     @classmethod
+    def list_classes(cls):
+        return uniq([w.wm_class for w in cls.list()])
+
+    @classmethod
+    def list_names(cls):
+        return uniq([w.name_class for w in cls.list()])
+
+    @classmethod
+    def list_roles(cls):
+        return uniq([w.wm_window_role for w in cls.list()])
+
+    @classmethod
     def by_name(cls, name):
         return [win for win in cls.list() if win.wm_name == name]
 
@@ -60,11 +141,35 @@
         return lst[0]
 
     def activate(self):
-        os.system('wmctrl -id -a %s' % self.id)
+        system('wmctrl -id -a %s' % self.id)
 
-    def resize_and_move(self, x, y, w, h):
+    def resize_and_move(self, x=None, y=None, w=None, h=None):
+        # XXX: the "move" part doesn't really work, it is affected by this:
+        # 
https://askubuntu.com/questions/576604/what-causes-the-deviation-in-the-wmctrl-window-move-command
+        if x is None:
+            x = self.x
+        if y is None:
+            y = self.y
+        if w is None:
+            w = self.w
+        if h is None:
+            h = self.h
         mvarg = '0,%d,%d,%d,%d' % (x, y, w, h)
-        os.system('wmctrl -i -r %s -e %s' % (self.id, mvarg))
+        system('wmctrl -i -r %s -e %s' % (self.id, mvarg))
+
+    def resize(self, w=None, h=None):
+        self.resize_and_move(w=w, h=h)
+
+    def move(self, x=None, y=None):
+        self.resize_and_move(x=x, y=y)
+
+    def sticky(self):
+        # -2 seems to work on kde plasma, not sure about the other WMs:
+        # 
https://unix.stackexchange.com/questions/11893/command-to-move-a-window
+        self.move_to_destktop(-2)
+
+    def move_to_destktop(self, n):
+        system('wmctrl -i -r %s -t %s' % (self.id, n))
 
     def set_geometry(self, geometry):
         dim, pos = geometry.split('+', 1)
@@ -72,16 +177,55 @@
         x, y = map(int, pos.split('+'))
         self.resize_and_move(x, y, w, h)
 
-    def set_properties(self,properties):
+    def set_properties(self, properties):
         proparg = ",".join(properties)
-        os.system('wmctrl -i -r %s -b %s' % (self.id,proparg))
+        system('wmctrl -i -r %s -b %s' % (self.id, proparg))
 
-def _wm_window_role(winid):
-    out = getoutput('xprop -id %s WM_WINDOW_ROLE' % winid)
-    try:
-        _, value = out.split(' = ')
-    except ValueError:
-        # probably xprop returned an error
-        return ''
-    else:
-        return value.strip('"')
+    def set_decorations(self, v):
+        import gtk.gdk
+        w = gtk.gdk.window_foreign_new(int(self.id, 16))
+        w.set_decorations(v)
+        gtk.gdk.window_process_all_updates()
+        gtk.gdk.flush()
+
+    def maximize(self, verb='add'):
+        "verb can be 'add', 'remove' or 'toggle'"
+        self.set_properties([verb, 'maximized_vert', 'maximized_horz'])
+
+    def unmaximize(self):
+        self.maximize('remove')
+
+
+@attr.s
+class Desktop(object):
+    num = attr.ib()
+    active = attr.ib()
+    name = attr.ib()
+
+    @classmethod
+    def list(cls):
+        out = getoutput('wmctrl -d')
+        desktops = []
+        for line in out.splitlines():
+            parts = line.split(None, 9)
+            parts = list(map(str.strip, parts))
+            num = int(parts[0])
+            active = parts[1] == '*'
+            name = parts[-1]
+            desktops.append(cls(num, active, name))
+        return desktops
+
+    @classmethod
+    def get_active(cls):
+        dlist = cls.list()
+        for d in dlist:
+            if d.active:
+                return d
+        # this should never happen, but who knows?
+        return None
+
+if __name__ == '__main__':
+    for w in Window.list():
+        print('{w.id:10s} {w.x:4d} {w.y:4d} {w.w:4d} {w.h:4d} {w.wm_name} - 
{w.wm_class} - {w.wm_window_role}'.format(w=w))
+
+    

Reply via email to