Hello community,

here is the log from the commit of package python-xapp for openSUSE:Leap:15.2 
checked in at 2020-02-19 18:49:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:15.2/python-xapp (Old)
 and      /work/SRC/openSUSE:Leap:15.2/.python-xapp.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-xapp"

Wed Feb 19 18:49:08 2020 rev:11 rq:777292 version:1.8.1

Changes:
--------
--- /work/SRC/openSUSE:Leap:15.2/python-xapp/python-xapp.changes        
2020-01-15 15:54:23.683630622 +0100
+++ /work/SRC/openSUSE:Leap:15.2/.python-xapp.new.26092/python-xapp.changes     
2020-02-19 18:49:08.447058639 +0100
@@ -1,0 +2,28 @@
+Sat Feb  8 07:18:12 UTC 2020 - Maurizio Galli <[email protected]>
+
+- Update to version 1.8.1
+  * icon chooser widget: fix kwargs to support current features 
+    correctly
+- Changes from versio 1.8.0
+  * Expose new features in the XAppIconChooserDialog to the 
+    settings widget (#10)
+
+-------------------------------------------------------------------
+Mon Jul  1 04:20:23 UTC 2019 - Dead Mozay <[email protected]>
+
+- Update to version 1.6.0:
+  * Add GSettingsWidgets and SettingsWidgets (#7)
+
+-------------------------------------------------------------------
+Fri Mar 15 04:10:00 UTC 2019 - Dead Mozay <[email protected]>
+
+- Update to version 1.4.0:
+  * Bump to version 1.4.0. 
+
+-------------------------------------------------------------------
+Thu Apr 19 20:07:54 UTC 2018 - [email protected]
+
+- Update to version 1.2.0:
+  * Properly bump version in setup.py.
+
+-------------------------------------------------------------------

Old:
----
  python-xapp-1.0.1.tar.gz

New:
----
  python-xapp-1.8.1.tar.gz

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

Other differences:
------------------
++++++ python-xapp.spec ++++++
--- /var/tmp/diff_new_pack.mmxq2m/_old  2020-02-19 18:49:08.723058933 +0100
+++ /var/tmp/diff_new_pack.mmxq2m/_new  2020-02-19 18:49:08.723058933 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-xapp
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,18 +12,18 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-xapp
-Version:        1.0.1
+Version:        1.8.1
 Release:        0
 Summary:        Python XApp library
-License:        GPL-2.0+
+License:        GPL-2.0-or-later
 Group:          Development/Languages/Python
-Url:            https://github.com/linuxmint/python-xapp
+URL:            https://github.com/linuxmint/python-xapp
 Source:         
https://github.com/linuxmint/%{name}/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz
 # PATCH-FEATURE-OPENSUSE python-xapp-xdgsu.patch -- Escalate privileges using 
xdg-su.
 Patch0:         python-xapp-xdgsu.patch
@@ -50,8 +50,8 @@
 %python_install
 
 %files %{python_files}
-%defattr(-,root,root)
-%doc COPYING debian/changelog
+%license COPYING
+%doc debian/changelog
 %{python_sitelib}/xapp/
 %{python_sitelib}/python_xapp-*.egg-info
 

++++++ python-xapp-1.0.1.tar.gz -> python-xapp-1.8.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-xapp-1.0.1/PKG-INFO 
new/python-xapp-1.8.1/PKG-INFO
--- old/python-xapp-1.0.1/PKG-INFO      2017-06-09 16:43:51.000000000 +0200
+++ new/python-xapp-1.8.1/PKG-INFO      2019-11-28 16:43:52.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: python-xapp
-Version: 1.0.0
+Version: 1.8.0
 Summary: The Xapp Python library.
 Home-page: http://github.com/linuxmint/python-xapp
 Author: Linux Mint
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-xapp-1.0.1/debian/changelog 
new/python-xapp-1.8.1/debian/changelog
--- old/python-xapp-1.0.1/debian/changelog      2017-06-09 16:43:51.000000000 
+0200
+++ new/python-xapp-1.8.1/debian/changelog      2019-11-28 16:43:52.000000000 
+0100
@@ -1,3 +1,36 @@
+python-xapp (1.8.1) tricia; urgency=medium
+
+  [ Stephen Collins ]
+  * icon chooser widget: fix kwargs to support current features correctly
+
+ -- Clement Lefebvre <[email protected]>  Thu, 28 Nov 2019 15:43:24 +0000
+
+python-xapp (1.8.0) tricia; urgency=medium
+
+  [ Stephen Collins ]
+  * Expose new features in the XAppIconChooserDialog to the settings widget 
(#10)
+
+ -- Clement Lefebvre <[email protected]>  Tue, 12 Nov 2019 11:19:42 +0100
+
+python-xapp (1.6.0) tessa; urgency=medium
+
+  * Add GSettingsWidgets and SettingsWidgets (#7)
+
+ -- Clement Lefebvre <[email protected]>  Fri, 17 May 2019 16:00:54 +0100
+
+python-xapp (1.4.0) tessa; urgency=medium
+
+  * 1.4.0
+
+ -- Clement Lefebvre <[email protected]>  Tue, 30 Oct 2018 15:28:33 +0000
+
+python-xapp (1.2.0) tara; urgency=medium
+
+  [ Björn Esser ]
+  * Properly bump version in setup.py (#5)
+
+ -- Clement Lefebvre <[email protected]>  Mon, 16 Apr 2018 15:40:51 +0100
+
 python-xapp (1.0.1) sonya; urgency=medium
 
   [ Clement Lefebvre ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-xapp-1.0.1/setup.py 
new/python-xapp-1.8.1/setup.py
--- old/python-xapp-1.0.1/setup.py      2017-06-09 16:43:51.000000000 +0200
+++ new/python-xapp-1.8.1/setup.py      2019-11-28 16:43:52.000000000 +0100
@@ -3,8 +3,8 @@
 from distutils.core import setup
 
 setup( name = "python-xapp",
-       version = "1.0.0",
-       description = "Python Xapp Library.",
+       version = "1.8.1",
+       description = "Python Xapp Library",
        maintainer = "Linux Mint",
        maintainer_email = "[email protected]",
        url = "http://github.com/linuxmint/python-xapp";,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-xapp-1.0.1/xapp/GSettingsWidgets.py 
new/python-xapp-1.8.1/xapp/GSettingsWidgets.py
--- old/python-xapp-1.0.1/xapp/GSettingsWidgets.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/python-xapp-1.8.1/xapp/GSettingsWidgets.py      2019-11-28 
16:43:52.000000000 +0100
@@ -0,0 +1,199 @@
+#!/usr/bin/python3
+
+from gi.repository import Gio, GLib
+from xapp.SettingsWidgets import *
+
+CAN_BACKEND = ["Switch", "SpinButton", "Entry", "TextView", "FontButton", 
"Range", "ComboBox",
+               "ColorChooser", "FileChooser", "IconChooser"]
+
+# Monkey patch Gio.Settings object
+def __setitem__(self, key, value):
+    # set_value() aborts the program on an unknown key
+    if key not in self:
+        raise KeyError('unknown key: %r' % (key,))
+
+    # determine type string of this key
+    range = self.get_range(key)
+    type_ = range.get_child_value(0).get_string()
+    v = range.get_child_value(1)
+    if type_ == 'type':
+        # v is boxed empty array, type of its elements is the allowed value 
type
+        assert v.get_child_value(0).get_type_string().startswith('a')
+        type_str = v.get_child_value(0).get_type_string()[1:]
+    elif type_ == 'enum':
+        # v is an array with the allowed values
+        assert v.get_child_value(0).get_type_string().startswith('a')
+        type_str = v.get_child_value(0).get_child_value(0).get_type_string()
+    elif type_ == 'flags':
+        # v is an array with the allowed values
+        assert v.get_child_value(0).get_type_string().startswith('a')
+        type_str = v.get_child_value(0).get_type_string()
+    elif type_ == 'range':
+        # type_str is a tuple giving the range
+        assert v.get_child_value(0).get_type_string().startswith('(')
+        type_str = v.get_child_value(0).get_type_string()[1]
+
+    if not self.set_value(key, GLib.Variant(type_str, value)):
+        raise ValueError("value '%s' for key '%s' is outside of valid range" % 
(value, key))
+
+def bind_with_mapping(self, key, widget, prop, flags, key_to_prop, 
prop_to_key):
+    self._ignore_key_changed = False
+
+    def key_changed(settings, key):
+        if self._ignore_key_changed:
+            return
+        self._ignore_prop_changed = True
+        widget.set_property(prop, key_to_prop(self[key]))
+        self._ignore_prop_changed = False
+
+    def prop_changed(widget, param):
+        if self._ignore_prop_changed:
+            return
+        self._ignore_key_changed = True
+        self[key] = prop_to_key(widget.get_property(prop))
+        self._ignore_key_changed = False
+
+    if not (flags & (Gio.SettingsBindFlags.SET | Gio.SettingsBindFlags.GET)): 
# ie Gio.SettingsBindFlags.DEFAULT
+        flags |= Gio.SettingsBindFlags.SET | Gio.SettingsBindFlags.GET
+    if flags & Gio.SettingsBindFlags.GET:
+        key_changed(self, key)
+        if not (flags & Gio.SettingsBindFlags.GET_NO_CHANGES):
+            self.connect('changed::' + key, key_changed)
+    if flags & Gio.SettingsBindFlags.SET:
+        widget.connect('notify::' + prop, prop_changed)
+    if not (flags & Gio.SettingsBindFlags.NO_SENSITIVITY):
+        self.bind_writable(key, widget, "sensitive", False)
+
+Gio.Settings.bind_with_mapping = bind_with_mapping
+Gio.Settings.__setitem__ = __setitem__
+
+class BinFileMonitor(GObject.GObject):
+    __gsignals__ = {
+        'changed': (GObject.SignalFlags.RUN_LAST, None, ()),
+    }
+    def __init__(self):
+        super(BinFileMonitor, self).__init__()
+
+        self.changed_id = 0
+
+        env = GLib.getenv("PATH")
+
+        if env == None:
+            env = "/bin:/usr/bin:."
+
+        self.paths = env.split(":")
+
+        self.monitors = []
+
+        for path in self.paths:
+            file = Gio.File.new_for_path(path)
+            mon = file.monitor_directory(Gio.FileMonitorFlags.SEND_MOVED, None)
+            mon.connect("changed", self.queue_emit_changed)
+            self.monitors.append(mon)
+
+    def _emit_changed(self):
+        self.emit("changed")
+        self.changed_id = 0
+        return False
+
+    def queue_emit_changed(self, file, other, event_type, data=None):
+        if self.changed_id > 0:
+            GLib.source_remove(self.changed_id)
+            self.changed_id = 0
+
+        self.changed_id = GLib.idle_add(self._emit_changed)
+
+file_monitor = None
+
+def get_file_monitor():
+    global file_monitor
+
+    if file_monitor == None:
+        file_monitor = BinFileMonitor()
+
+    return file_monitor
+
+# This class is not meant to be used directly - it is only a backend for the
+# settings widgets to enable them to bind attributes to gsettings keys. To use
+# the gesttings backend, simply add the "GSettings" prefix to the beginning
+# of the widget class name. The arguments of the backended class will be
+# (label, schema, key, any additional widget-specific args and keyword args).
+# (Note: this only works for classes that are gsettings compatible.)
+#
+# If you wish to make a new widget available to be backended, place it in the
+# CAN_BACKEND list. In addition, you will need to add the following attributes
+# to the widget class:
+#
+# bind_dir - (Gio.SettingsBindFlags) flags to define the binding direction or
+#            None if you don't want the setting bound (for example if the
+#            setting effects multiple attributes)
+# bind_prop - (string) the attribute in the widget that will be bound to the
+#             setting. This property may be omitted if bind_dir is None
+# bind_object - (optional) the object to which to bind to (only needed if the
+#               attribute to be bound is not a property of self.content_widget)
+# map_get, map_set - (function, optional) a function to map between setting and
+#                    bound attribute. May also be passed as a keyword arg 
during
+#                    instantiation. These will be ignored if bind_dir=None
+# set_rounding - (function, optional) To be used to set the digits to round to
+#                if the setting is an integer
+class PXGSettingsBackend(object):
+    def bind_settings(self):
+        if hasattr(self, "set_rounding"):
+            vtype = self.settings.get_value(self.key).get_type_string()
+            if vtype in ["i", "u"]:
+                self.set_rounding(0)
+        if hasattr(self, "bind_object"):
+            bind_object = self.bind_object
+        else:
+            bind_object = self.content_widget
+        if hasattr(self, "map_get") or hasattr(self, "map_set"):
+            self.settings.bind_with_mapping(self.key, bind_object, 
self.bind_prop, self.bind_dir, self.map_get, self.map_set)
+        elif self.bind_dir != None:
+            self.settings.bind(self.key, bind_object, self.bind_prop, 
self.bind_dir)
+        else:
+            self.settings.connect("changed::"+self.key, 
self.on_setting_changed)
+            self.settings.bind_writable(self.key, bind_object, "sensitive", 
False)
+            self.on_setting_changed()
+            self.connect_widget_handlers()
+
+    def set_value(self, value):
+        self.settings[self.key] = value
+
+    def get_value(self):
+        return self.settings[self.key]
+
+    def get_range(self):
+        range = self.settings.get_range(self.key)
+        if range[0] == "range":
+            return [range[1][0], range[1][1]]
+        else:
+            return None
+
+    def on_setting_changed(self, *args):
+        raise NotImplementedError("SettingsWidget class must implement 
on_setting_changed().")
+
+    def connect_widget_handlers(self, *args):
+        if self.bind_dir == None:
+            raise NotImplementedError("SettingsWidget classes with no 
.bind_dir must implement connect_widget_handlers().")
+
+def g_settings_factory(subclass):
+    class NewClass(globals()[subclass], PXGSettingsBackend):
+        def __init__(self, label, schema, key, *args, **kwargs):
+            self.key = key
+            if schema not in settings_objects:
+                settings_objects[schema] = Gio.Settings.new(schema)
+            self.settings = settings_objects[schema]
+
+            if "map_get" in kwargs:
+                self.map_get = kwargs["map_get"]
+                del kwargs["map_get"]
+            if "map_set" in kwargs:
+                self.map_set = kwargs["map_set"]
+                del kwargs["map_set"]
+
+            super(NewClass, self).__init__(label, *args, **kwargs)
+            self.bind_settings()
+    return NewClass
+
+for widget in CAN_BACKEND:
+    globals()["GSettings"+widget] = g_settings_factory(widget)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-xapp-1.0.1/xapp/SettingsWidgets.py 
new/python-xapp-1.8.1/xapp/SettingsWidgets.py
--- old/python-xapp-1.0.1/xapp/SettingsWidgets.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/python-xapp-1.8.1/xapp/SettingsWidgets.py       2019-11-28 
16:43:52.000000000 +0100
@@ -0,0 +1,729 @@
+#!/usr/bin/python3
+
+import math
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('XApp', '1.0')
+from gi.repository import Gio, Gtk, GObject, Gdk, GLib, XApp
+
+settings_objects = {}
+
+class EditableEntry (Gtk.Stack):
+
+    __gsignals__ = {
+        'changed': (GObject.SignalFlags.RUN_FIRST, None,
+                    (str,))
+    }
+
+    def __init__ (self):
+        super(EditableEntry, self).__init__()
+
+        self.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
+        self.set_transition_duration(150)
+
+        self.label = Gtk.Label()
+        self.entry = Gtk.Entry()
+        self.button = Gtk.Button()
+
+        self.button.set_alignment(1.0, 0.5)
+        self.button.set_relief(Gtk.ReliefStyle.NONE)
+        self.add_named(self.button, "button");
+        self.add_named(self.entry, "entry");
+        self.set_visible_child_name("button")
+        self.editable = False
+        self.current_text = None
+        self.show_all()
+
+        self.button.connect("released", self._on_button_clicked)
+        self.button.connect("activate", self._on_button_clicked)
+        self.entry.connect("activate", self._on_entry_validated)
+        self.entry.connect("changed", self._on_entry_changed)
+        self.entry.connect("focus-out-event", self._on_focus_lost)
+
+    def set_text(self, text):
+        self.button.set_label(text)
+        self.entry.set_text(text)
+        self.current_text = text
+
+    def _on_focus_lost(self, widget, event):
+        self.button.set_label(self.current_text)
+        self.entry.set_text(self.current_text)
+
+        self.set_editable(False)
+
+    def _on_button_clicked(self, button):
+        self.set_editable(True)
+        self.entry.grab_focus()
+
+    def _on_entry_validated(self, entry):
+        self.set_editable(False)
+        self.emit("changed", entry.get_text())
+        self.current_text = entry.get_text()
+
+    def _on_entry_changed(self, entry):
+        self.button.set_label(entry.get_text())
+
+    def set_editable(self, editable):
+        if (editable):
+            self.set_visible_child_name("entry")
+        else:
+            self.set_visible_child_name("button")
+        self.editable = editable
+
+    def set_tooltip_text(self, tooltip):
+        self.button.set_tooltip_text(tooltip)
+
+    def get_editable(self):
+        return self.editable
+
+    def get_text(self):
+        return self.entry.get_text()
+
+class SettingsStack(Gtk.Stack):
+    def __init__(self):
+        Gtk.Stack.__init__(self)
+        self.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
+        self.set_transition_duration(150)
+        self.expand = True
+
+class SettingsRevealer(Gtk.Revealer):
+    def __init__(self, schema=None, key=None, values=None, check_func=None):
+        Gtk.Revealer.__init__(self)
+
+        self.check_func = check_func
+
+        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15)
+        Gtk.Revealer.add(self, self.box)
+
+        self.set_transition_type(Gtk.RevealerTransitionType.SLIDE_DOWN)
+        self.set_transition_duration(150)
+
+        if schema:
+            self.settings = Gio.Settings.new(schema)
+            # if there aren't values or a function provided to determine 
visibility we can do a simple bind
+            if values is None and check_func is None:
+                self.settings.bind(key, self, "reveal-child", 
Gio.SettingsBindFlags.GET)
+            else:
+                self.values = values
+                self.settings.connect("changed::" + key, 
self.on_settings_changed)
+                self.on_settings_changed(self.settings, key)
+
+    def add(self, widget):
+        self.box.pack_start(widget, False, True, 0)
+
+    #only used when checking values
+    def on_settings_changed(self, settings, key):
+        value = settings.get_value(key).unpack()
+        if self.check_func is None:
+            self.set_reveal_child(value in self.values)
+        else:
+            self.set_reveal_child(self.check_func(value, self.values))
+
+class SettingsPage(Gtk.Box):
+    def __init__(self):
+        Gtk.Box.__init__(self)
+        self.set_orientation(Gtk.Orientation.VERTICAL)
+        self.set_spacing(30)
+        self.set_margin_left(80)
+        self.set_margin_right(80)
+        self.set_margin_top(15)
+        self.set_margin_bottom(15)
+
+    def add_section(self, title=None, subtitle=None):
+        section = SettingsSection(title, subtitle)
+        self.pack_start(section, False, False, 0)
+
+        return section
+
+    def add_reveal_section(self, title, schema=None, key=None, values=None, 
revealer=None):
+        section = SettingsSection(title)
+        if revealer is None:
+            revealer = SettingsRevealer(schema, key, values)
+        revealer.add(section)
+        section._revealer = revealer
+        self.pack_start(revealer, False, False, 0)
+
+        return section
+
+class SettingsSection(Gtk.Box):
+    def __init__(self, title=None, subtitle=None):
+        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
+        self.set_spacing(10)
+
+        if title or subtitle:
+            header_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+            header_box.set_spacing(5)
+            self.add(header_box)
+
+            if title:
+                label = Gtk.Label()
+                label.set_markup("<b>%s</b>" % title)
+                label.set_alignment(0, 0.5)
+                header_box.add(label)
+
+            if subtitle:
+                sub = Gtk.Label()
+                sub.set_text(subtitle)
+                sub.get_style_context().add_class("dim-label")
+                sub.set_alignment(0, 0.5)
+                header_box.add(sub)
+
+        self.frame = Gtk.Frame()
+        self.frame.set_shadow_type(Gtk.ShadowType.IN)
+        frame_style = self.frame.get_style_context()
+        frame_style.add_class("view")
+        self.size_group = Gtk.SizeGroup()
+        self.size_group.set_mode(Gtk.SizeGroupMode.VERTICAL)
+
+        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        self.frame.add(self.box)
+
+        self.need_separator = False
+
+    def add_row(self, widget):
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        if self.need_separator:
+            vbox.add(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL))
+        list_box = Gtk.ListBox()
+        list_box.set_selection_mode(Gtk.SelectionMode.NONE)
+        row = Gtk.ListBoxRow(can_focus=False)
+        row.add(widget)
+        if isinstance(widget, Switch):
+            list_box.connect("row-activated", widget.clicked)
+        list_box.add(row)
+        vbox.add(list_box)
+        self.box.add(vbox)
+
+        if self.frame.get_parent() is None:
+            self.add(self.frame)
+
+        self.need_separator = True
+
+    def add_reveal_row(self, widget, schema=None, key=None, values=None, 
check_func=None, revealer=None):
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        if self.need_separator:
+            vbox.add(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL))
+        list_box = Gtk.ListBox()
+        list_box.set_selection_mode(Gtk.SelectionMode.NONE)
+        row = Gtk.ListBoxRow(can_focus=False)
+        row.add(widget)
+        if isinstance(widget, Switch):
+            list_box.connect("row-activated", widget.clicked)
+        list_box.add(row)
+        vbox.add(list_box)
+        if revealer is None:
+            revealer = SettingsRevealer(schema, key, values, check_func)
+        widget.revealer = revealer
+        revealer.add(vbox)
+        self.box.add(revealer)
+
+        self.need_separator = True
+
+        return revealer
+
+    def add_note(self, text):
+        label = Gtk.Label()
+        label.set_alignment(0, 0.5)
+        label.set_markup(text)
+        label.set_line_wrap(True)
+        self.add(label)
+        return label
+
+class SettingsWidget(Gtk.Box):
+    def __init__(self, dep_key=None):
+        Gtk.Box.__init__(self)
+        self.set_orientation(Gtk.Orientation.HORIZONTAL)
+        self.set_spacing(20)
+        self.set_border_width(5)
+        self.set_margin_left(20)
+        self.set_margin_right(20)
+
+        if dep_key:
+            self.set_dep_key(dep_key)
+
+    def set_dep_key(self, dep_key):
+        flag = Gio.SettingsBindFlags.GET
+        if dep_key[0] == "!":
+            dep_key = dep_key[1:]
+            flag |= Gio.Settings.BindFlags.INVERT_BOOLEAN
+
+        split = dep_key.split("/")
+        dep_settings = Gio.Settings.new(split[0])
+        dep_settings.bind(split[1], self, "sensitive", flag)
+
+    def add_to_size_group(self, group):
+        group.add_widget(self.content_widget)
+
+    def fill_row(self):
+        self.set_border_width(0)
+        self.set_margin_left(0)
+        self.set_margin_right(0)
+
+    def get_settings(self, schema):
+        global settings_objects
+        try:
+            return settings_objects[schema]
+        except:
+            settings_objects[schema] = Gio.Settings.new(schema)
+            return settings_objects[schema]
+
+class SettingsLabel(Gtk.Label):
+    def __init__(self, text=None):
+        Gtk.Label.__init__(self)
+        if text:
+            self.set_label(text)
+
+        self.set_alignment(0.0, 0.5)
+        self.set_line_wrap(True)
+
+    def set_label_text(self, text):
+        self.set_label(text)
+
+class Switch(SettingsWidget):
+    bind_prop = "active"
+    bind_dir = Gio.SettingsBindFlags.DEFAULT
+
+    def __init__(self, label, dep_key=None, tooltip=""):
+        super(Switch, self).__init__(dep_key=dep_key)
+
+        self.content_widget = Gtk.Switch(valign=Gtk.Align.CENTER)
+        self.label = SettingsLabel(label)
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, False, False, 0)
+
+        self.set_tooltip_text(tooltip)
+
+    def clicked(self, *args):
+        if self.is_sensitive():
+            self.content_widget.set_active(not 
self.content_widget.get_active())
+
+class SpinButton(SettingsWidget):
+    bind_prop = "value"
+    bind_dir = Gio.SettingsBindFlags.GET
+
+    def __init__(self, label, units="", mini=None, maxi=None, step=1, 
page=None, size_group=None, dep_key=None, tooltip=""):
+        super(SpinButton, self).__init__(dep_key=dep_key)
+
+        self.timer = None
+
+        if units:
+            label += " (%s)" % units
+        self.label = SettingsLabel(label)
+        self.content_widget = Gtk.SpinButton()
+
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, False, False, 0)
+
+        range = self.get_range()
+        if mini == None or maxi == None:
+            mini = range[0]
+            maxi = range[1]
+        elif range is not None:
+            mini = max(mini, range[0])
+            maxi = min(maxi, range[1])
+
+        if not page:
+            page = step
+
+        self.content_widget.set_range(mini, maxi)
+        self.content_widget.set_increments(step, page)
+
+        digits = 0
+        if (step and '.' in str(step)):
+            digits = len(str(step).split('.')[1])
+        self.content_widget.set_digits(digits)
+
+        self.content_widget.connect("value-changed", self.apply_later)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+    def apply_later(self, *args):
+        def apply(self):
+            self.set_value(self.content_widget.get_value())
+            self.timer = None
+
+        if self.timer:
+            GLib.source_remove(self.timer)
+        self.timer = GLib.timeout_add(300, apply, self)
+
+class Entry(SettingsWidget):
+    bind_prop = "text"
+    bind_dir = Gio.SettingsBindFlags.DEFAULT
+
+    def __init__(self, label, expand_width=False, size_group=None, 
dep_key=None, tooltip=""):
+        super(Entry, self).__init__(dep_key=dep_key)
+
+        self.label = SettingsLabel(label)
+        self.content_widget = Gtk.Entry()
+        self.content_widget.set_valign(Gtk.Align.CENTER)
+
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, expand_width, expand_width, 0)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+class TextView(SettingsWidget):
+    bind_prop = "text"
+    bind_dir = Gio.SettingsBindFlags.DEFAULT
+
+    def __init__(self, label, height=200, dep_key=None, tooltip=""):
+        super(TextView, self).__init__(dep_key=dep_key)
+
+        self.set_orientation(Gtk.Orientation.VERTICAL)
+        self.set_spacing(8)
+
+        self.label = Gtk.Label.new(label)
+        self.label.set_halign(Gtk.Align.CENTER)
+
+        self.scrolledwindow = Gtk.ScrolledWindow(hadjustment=None, 
vadjustment=None)
+        self.scrolledwindow.set_size_request(width=-1, height=height)
+        
self.scrolledwindow.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC,
+                                       
vscrollbar_policy=Gtk.PolicyType.AUTOMATIC)
+        self.scrolledwindow.set_shadow_type(type=Gtk.ShadowType.ETCHED_IN)
+        self.content_widget = Gtk.TextView()
+        self.content_widget.set_border_width(3)
+        self.content_widget.set_wrap_mode(wrap_mode=Gtk.WrapMode.NONE)
+        self.bind_object = self.content_widget.get_buffer()
+
+        self.pack_start(self.label, False, False, 0)
+        self.add(self.scrolledwindow)
+        self.scrolledwindow.add(self.content_widget)
+        self._value_changed_timer = None
+
+class FontButton(SettingsWidget):
+    bind_prop = "font-name"
+    bind_dir = Gio.SettingsBindFlags.DEFAULT
+
+    def __init__(self, label, size_group=None, dep_key=None, tooltip=""):
+        super(FontButton, self).__init__(dep_key=dep_key)
+
+        self.label = SettingsLabel(label)
+
+        self.content_widget = Gtk.FontButton()
+        self.content_widget.set_valign(Gtk.Align.CENTER)
+
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, False, False, 0)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+class Range(SettingsWidget):
+    bind_prop = "value"
+    bind_dir = Gio.SettingsBindFlags.GET | Gio.SettingsBindFlags.NO_SENSITIVITY
+
+    def __init__(self, label, min_label="", max_label="", mini=None, 
maxi=None, step=None, invert=False, log=False, show_value=True, dep_key=None, 
tooltip="", flipped=False, units=""):
+        super(Range, self).__init__(dep_key=dep_key)
+
+        self.set_orientation(Gtk.Orientation.VERTICAL)
+        self.set_spacing(0)
+
+        self.log = log
+        self.invert = invert
+        self.flipped = flipped
+        self.timer = None
+        self.value = 0
+
+        hbox = Gtk.Box()
+
+        if units:
+            label += " ({})".format(units)
+
+        self.label = Gtk.Label.new(label)
+        self.label.set_halign(Gtk.Align.CENTER)
+
+        self.min_label= Gtk.Label()
+        self.max_label = Gtk.Label()
+        self.min_label.set_alignment(1.0, 0.75)
+        self.max_label.set_alignment(1.0, 0.75)
+        self.min_label.set_margin_right(6)
+        self.max_label.set_margin_left(6)
+        self.min_label.set_markup("<i><small>%s</small></i>" % min_label)
+        self.max_label.set_markup("<i><small>%s</small></i>" % max_label)
+
+        range = self.get_range()
+        if mini == None or maxi == None:
+            mini = range[0]
+            maxi = range[1]
+        elif range is not None:
+            mini = max(mini, range[0])
+            maxi = min(maxi, range[1])
+
+        if log:
+            mini = math.log(mini)
+            maxi = math.log(maxi)
+            if self.flipped:
+                self.map_get = lambda x: -1 * (math.log(x))
+                self.map_set = lambda x: math.exp(x)
+            else:
+                self.map_get = lambda x: math.log(x)
+                self.map_set = lambda x: math.exp(x)
+        elif self.flipped:
+            self.map_get = lambda x: x * -1
+            self.map_set = lambda x: x * -1
+
+        if self.flipped:
+            tmp_mini = mini
+            mini = maxi * -1
+            maxi = tmp_mini * -1
+
+        if step is None:
+            self.step = (maxi - mini) * 0.02
+        else:
+            self.step = math.log(step) if log else step
+
+        self.content_widget = 
Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, mini, maxi, self.step)
+        self.content_widget.set_inverted(invert)
+        self.content_widget.set_draw_value(show_value and not self.flipped)
+        self.bind_object = self.content_widget.get_adjustment()
+
+        if invert:
+            self.step *= -1 # Gtk.Scale.new_with_range want a positive value, 
but our custom scroll handler wants a negative value
+
+        hbox.pack_start(self.min_label, False, False, 0)
+        hbox.pack_start(self.content_widget, True, True, 0)
+        hbox.pack_start(self.max_label, False, False, 0)
+
+        self.pack_start(self.label, False, False, 0)
+        self.pack_start(hbox, True, True, 6)
+
+        self.content_widget.connect("scroll-event", self.on_scroll_event)
+        self.content_widget.connect("value-changed", self.apply_later)
+
+        self.set_tooltip_text(tooltip)
+
+    def apply_later(self, *args):
+        def apply(self):
+            if self.log:
+                self.set_value(math.exp(abs(self.content_widget.get_value())))
+            else:
+                if self.flipped:
+                    self.set_value(self.content_widget.get_value() * -1)
+                else:
+                    self.set_value(self.content_widget.get_value())
+            self.timer = None
+
+        if self.timer:
+            GLib.source_remove(self.timer)
+        self.timer = GLib.timeout_add(300, apply, self)
+
+    def on_scroll_event(self, widget, event):
+        found, delta_x, delta_y = event.get_scroll_deltas()
+
+        # If you scroll up, delta_y < 0. This is a weird world
+        widget.set_value(widget.get_value() - delta_y * self.step)
+
+        return True
+
+    def add_mark(self, value, position, markup):
+        if self.log:
+            self.content_widget.add_mark(math.log(value), position, markup)
+        else:
+            self.content_widget.add_mark(value, position, markup)
+
+    def set_rounding(self, digits):
+        if not self.log:
+            self.content_widget.set_round_digits(digits)
+            self.content_widget.set_digits(digits)
+
+class ComboBox(SettingsWidget):
+    bind_dir = None
+
+    def __init__(self, label, options=[], valtype=None, size_group=None, 
dep_key=None, tooltip=""):
+        super(ComboBox, self).__init__(dep_key=dep_key)
+
+        self.valtype = valtype
+        self.option_map = {}
+
+        self.label = SettingsLabel(label)
+
+        self.content_widget = Gtk.ComboBox()
+        renderer_text = Gtk.CellRendererText()
+        self.content_widget.pack_start(renderer_text, True)
+        self.content_widget.add_attribute(renderer_text, "text", 1)
+
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, False, False, 0)
+        self.content_widget.set_valign(Gtk.Align.CENTER)
+
+        self.set_options(options)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+    def on_my_value_changed(self, widget):
+        tree_iter = widget.get_active_iter()
+        if tree_iter != None:
+            self.value = self.model[tree_iter][0]
+            self.set_value(self.value)
+
+    def on_setting_changed(self, *args):
+        self.value = self.get_value()
+        try:
+            self.content_widget.set_active_iter(self.option_map[self.value])
+        except:
+            self.content_widget.set_active_iter(None)
+
+    def connect_widget_handlers(self, *args):
+        self.content_widget.connect('changed', self.on_my_value_changed)
+
+    def set_options(self, options):
+        if self.valtype is not None:
+            var_type = self.valtype
+        else:
+            # assume all keys are the same type (mixing types is going to 
cause an error somewhere)
+            var_type = type(options[0][0])
+        self.model = Gtk.ListStore(var_type, str)
+
+        for option in options:
+            self.option_map[option[0]] = self.model.append([option[0], 
option[1]])
+
+        self.content_widget.set_model(self.model)
+        self.content_widget.set_id_column(0)
+
+class ColorChooser(SettingsWidget):
+    bind_dir = None
+
+    def __init__(self, label, legacy_string=False, size_group=None, 
dep_key=None, tooltip=""):
+        super(ColorChooser, self).__init__(dep_key=dep_key)
+        # note: Gdk.Color is deprecated in favor of Gdk.RGBA, but as the hex 
format is still used
+        # in some places (most notably the desktop background handling in 
cinnamon-desktop) we
+        # still support it for now by adding the legacy_string argument
+        self.legacy_string = legacy_string
+
+        self.label = SettingsLabel(label)
+        self.content_widget = Gtk.ColorButton()
+        self.content_widget.set_use_alpha(True)
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, False, False, 0)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+    def on_setting_changed(self, *args):
+        color_string = self.get_value()
+        rgba = Gdk.RGBA()
+        rgba.parse(color_string)
+        self.content_widget.set_rgba(rgba)
+
+    def connect_widget_handlers(self, *args):
+        self.content_widget.connect('color-set', self.on_my_value_changed)
+
+    def on_my_value_changed(self, widget):
+        if self.legacy_string:
+            color_string = self.content_widget.get_color().to_string()
+        else:
+            color_string = self.content_widget.get_rgba().to_string()
+        self.set_value(color_string)
+
+class FileChooser(SettingsWidget):
+    bind_dir = None
+
+    def __init__(self, label, dir_select=False, size_group=None, dep_key=None, 
tooltip=""):
+        super(FileChooser, self).__init__(dep_key=dep_key)
+        if dir_select:
+            action = Gtk.FileChooserAction.SELECT_FOLDER
+        else:
+            action = Gtk.FileChooserAction.OPEN
+
+        self.label = SettingsLabel(label)
+        self.content_widget = Gtk.FileChooserButton(action=action)
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, False, False, 0)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+    def on_file_selected(self, *args):
+        self.set_value(self.content_widget.get_uri())
+
+    def on_setting_changed(self, *args):
+        self.content_widget.set_uri(self.get_value())
+
+    def connect_widget_handlers(self, *args):
+        self.content_widget.connect("file-set", self.on_file_selected)
+
+class IconChooser(SettingsWidget):
+    bind_prop = "icon"
+    bind_dir = Gio.SettingsBindFlags.DEFAULT
+
+    def __init__(self, label, default_icon=None, icon_categories=[], 
default_category=None, expand_width=False, size_group=None, dep_key=None, 
tooltip=""):
+        super(IconChooser, self).__init__(dep_key=dep_key)
+
+        self.label = SettingsLabel(label)
+
+        self.content_widget = XApp.IconChooserButton()
+        self.content_widget.set_icon_size(Gtk.IconSize.BUTTON)
+
+        dialog = self.content_widget.get_dialog()
+        if default_icon:
+            dialog.set_default_icon(default_icon)
+
+        for category in icon_categories:
+            dialog.add_custom_category(category['name'], category['icons'])
+
+        if default_category is not None:
+            self.content_widget.set_default_category(default_category)
+
+        self.pack_start(self.label, False, False, 0)
+        self.pack_end(self.content_widget, expand_width, expand_width, 0)
+
+        self.set_tooltip_text(tooltip)
+
+        if size_group:
+            self.add_to_size_group(size_group)
+
+class Button(SettingsWidget):
+    def __init__(self, label, callback=None):
+        super(Button, self).__init__()
+        self.label = label
+        self.callback = callback
+
+        self.content_widget = Gtk.Button(label=label)
+        self.pack_start(self.content_widget, True, True, 0)
+        self.content_widget.connect("clicked", self._on_button_clicked)
+
+    def _on_button_clicked(self, *args):
+        if self.callback is not None:
+            self.callback(self)
+        elif hasattr(self, "on_activated"):
+            self.on_activated()
+        else:
+            print("warning: button '%s' does nothing" % self.label)
+
+    def set_label(self, label):
+        self.label = label
+        self.content_widget.set_label(label)
+
+class Text(SettingsWidget):
+    def __init__(self, label, align=Gtk.Align.START):
+        super(Text, self).__init__()
+        self.label = label
+
+        if align == Gtk.Align.END:
+            xalign = 1.0
+            justification = Gtk.Justification.RIGHT
+        elif align == Gtk.Align.CENTER:
+            xalign = 0.5
+            justification = Gtk.Justification.CENTER
+        else: # START and FILL align left
+            xalign = 0
+            justification = Gtk.Justification.LEFT
+
+        self.content_widget = Gtk.Label(label, halign=align, xalign=xalign, 
justify=justification)
+        self.content_widget.set_line_wrap(True)
+        self.pack_start(self.content_widget, True, True, 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-xapp-1.0.1/xapp/__init__.py 
new/python-xapp-1.8.1/xapp/__init__.py
--- old/python-xapp-1.0.1/xapp/__init__.py      2017-06-09 16:43:51.000000000 
+0200
+++ new/python-xapp-1.8.1/xapp/__init__.py      2019-11-28 16:43:52.000000000 
+0100
@@ -1,3 +1,3 @@
-__all__ = [ "os" ]
+__all__ = [ "os", "GSettingsWidgets", "SettingsWidgets" ]
 
-__version__ = "1.0.0"
+__version__ = "1.8.0"


Reply via email to