[Libreoffice-commits] core.git: bin/gla11y solenv/gbuild solenv/sanitizers

Samuel Thibault sthibault at hypra.fr
Tue Mar 27 12:46:58 UTC 2018


 bin/gla11y                              | 1145 ++++++++++++++++++++++++++++----
 solenv/gbuild/UIConfig.mk               |   67 +
 solenv/gbuild/platform/com_GCC_class.mk |    2 
 solenv/gbuild/platform/com_MSC_class.mk |    2 
 solenv/sanitizers/ui/cui.suppr          |   11 
 solenv/sanitizers/ui/svt.suppr          |    4 
 solenv/sanitizers/ui/svx.suppr          |   18 
 7 files changed, 1100 insertions(+), 149 deletions(-)

New commits:
commit d0f1a431eab9a7a503bf6487732eeaec0e881053
Author: Samuel Thibault <sthibault at hypra.fr>
Date:   Mon Mar 12 18:28:06 2018 +0100

    gla11y: update heuristics but don't enable warnings yet
    
    This updates gla11y with all heuristics to detect orphan labels and widgets
    without too many false positives.
    
    This updates gbuild to tell gla11y to only emit errors about undefined
    targets and about orphan warnings for GtkScale (as was the case with
    previous versions). More errors and warnings will be enabled progressively
    later on.
    
    Change-Id: I96580eb0eb8eb327f0f54563d7976a5148e9531a
    Reviewed-on: https://gerrit.libreoffice.org/51161
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/bin/gla11y b/bin/gla11y
index fa6e7281a0cd..e19e580d0d4f 100755
--- a/bin/gla11y
+++ b/bin/gla11y
@@ -36,23 +36,263 @@ try:
     lxml = True
 except ImportError:
     if sys.version_info < (2,7):
+        print("gla11y needs lxml or python >= 2.7")
         exit()
     import xml.etree.ElementTree as ET
     lxml = False
 
+# Toplevel widgets
+widgets_toplevel = [
+    'GtkWindow',
+    'GtkOffscreenWindow',
+    'GtkApplicationWindow',
+    'GtkDialog',
+    'GtkAboutDialog',
+    'GtkFileChooserDialog',
+    'GtkColorChooserDialog',
+    'GtkFontChooserDialog',
+    'GtkMessageDialog',
+    'GtkRecentChooserDialog',
+    'GtkAssistant',
+    'GtkAppChooserDialog',
+    'GtkPrintUnixDialog',
+    'GtkShortcutsWindow',
+]
+
+widgets_ignored = widgets_toplevel + [
+    # Containers
+    'GtkBox',
+    'GtkGrid',
+    'GtkNotebook',
+    'GtkFrame',
+    'GtkAspectFrame',
+    'GtkListBox',
+    'GtkFlowBox',
+    'GtkOverlay',
+    'GtkMenuBar',
+    'GtkToolbar',
+    'GtkToolpalette',
+    'GtkPaned',
+    'GtkHPaned',
+    'GtkVPaned',
+    'GtkButtonBox',
+    'GtkHButtonBox',
+    'GtkVButtonBox',
+    'GtkLayout',
+    'GtkFixed',
+    'GtkEventBox',
+    'GtkExpander',
+    'GtkViewport',
+    'GtkScrolledWindow',
+    'GtkAlignment',
+    'GtkRevealer',
+    'GtkSearchBar',
+    'GtkHeaderBar',
+    'GtkStack',
+    'GtkStackSwticher',
+    'GtkPopover',
+    'GtkPopoverMenu',
+    'GtkActionBar',
+    'GtkHandleBox',
+    'GtkShortcutsSection',
+    'GtkShortcutsGroup',
+    'GtkTable',
+
+    'GtkVBox',
+    'GtkHBox',
+    'GtkToolItem',
+    'GtkMenu',
+
+    # Invisible actions
+    'GtkSeparator',
+    'GtkHSeparator',
+    'GtkVSeparator',
+    'GtkAction',
+    'GtkToggleAction',
+    'GtkActionGroup',
+    'GtkCellRendererGraph',
+    'GtkCellRendererPixbuf',
+    'GtkCellRendererProgress',
+    'GtkCellRendererSpin',
+    'GtkCellRendererText',
+    'GtkCellRendererToggle',
+    'GtkSeparatorMenuItem',
+    'GtkSeparatorToolItem',
+
+    # Storage objects
+    'GtkListStore',
+    'GtkTreeStore',
+    'GtkTreeModelFilter',
+    'GtkTreeModelSort',
+
+    'GtkEntryBuffer',
+    'GtkTextBuffer',
+    'GtkTextTag',
+    'GtkTextTagTable',
+
+    'GtkSizeGroup',
+    'GtkWindowGroup',
+    'GtkAccelGroup',
+    'GtkAdjustment',
+    'GtkEntryCompletion',
+    'GtkIconFactory',
+    'GtkStatusIcon',
+    'GtkFileFilter',
+    'GtkRecentFilter',
+    'GtkRecentManager',
+    'GThemedIcon',
+
+    'GtkTreeSelection',
+
+    'GtkListBoxRow',
+
+    # Useless to label
+    'GtkScrollbar',
+    'GtkHScrollbar',
+    'GtkStatusbar',
+    'GtkInfoBar',
+
+    # These are actually labels
+    'GtkLinkButton',
+
+    # This precisely give a11y information :)
+    'AtkObject',
+]
+
+widgets_suffixignored = [
+]
+
+# These widgets always need a label
+widgets_needlabel = [
+    'GtkEntry',
+    'GtkSearchEntry',
+    'GtkScale',
+    'GtkHScale',
+    'GtkVScale',
+    'GtkSpinButton',
+    'GtkSwitch',
+]
+
+# These widgets normally have their own label
+widgets_buttons = [
+    'GtkButton',
+    'GtkToolButton',
+    'GtkToggleButton',
+    'GtkToggleToolButton',
+    'GtkRadioButton',
+    'GtkRadioToolButton',
+    'GtkCheckButton',
+    'GtkModelButton',
+    'GtkLockButton',
+    'GtkColorButton',
+    'GtkMenuButton',
+
+    'GtkMenuItem',
+    'GtkImageMenuItem',
+    'GtkMenuToolButton',
+    'GtkRadioMenuItem',
+    'GtkCheckMenuItem',
+]
+
+# These widgets are labels that can label other widgets
+widgets_labels = [
+    'GtkLabel',
+    'GtkAccelLabel',
+]
+
+# The rest should probably be labelled if there are orphan labels
+
+# GtkSpinner
+# GtkProgressBar
+# GtkLevelBar
+
+# GtkComboBox
+# GtkComboBoxText
+# GtkFileChooserButton
+# GtkAppChooserButton
+# GtkFontButton
+# GtkCalendar
+# GtkColorChooserWidget
+
+# GtkCellView
+# GtkTreeView
+# GtkTreeViewColumn
+# GtkTextView
+# GtkIconView
+
+# GtkImage
+# GtkArrow
+# GtkDrawingArea
+
+# GtkScaleButton
+# GtkVolumeButton
+
+
+# TODO:
+# GtkColorPlane ?
+# GtkColorScale ?
+# GtkColorSwatch ?
+# GtkFileChooserWidget ?
+# GtkFishbowl ?
+# GtkFontChooserWidget ?
+# GtkIcon ?
+# GtkInspector* ?
+# GtkMagnifier ?
+# GtkPathBar ?
+# GtkPlacesSidebar ?
+# GtkPlacesView ?
+# GtkPrinterOptionWidget ?
+# GtkStackCombo ?
+# GtkStackSidebar ?
+
 progname = os.path.basename(sys.argv[0])
+
 suppressions = {}
+ids = {}
+ids_dup = {}
+labelled_by_elm = {}
+label_for_elm = {}
+mnemonic_for_elm = {}
+
 gen_suppr = None
 gen_supprfile = None
 suppr_prefix = ""
 outfile = None
+
 pflag = False
-Werror = False
-Wnone = False
+
+warn_orphan_labels = True
+
 errors = 0
 errexists = 0
 warnings = 0
 warnexists = 0
+fatals = 0
+fatalexists = 0
+
+enables = [ ]
+dofatals = [ ]
+
+#
+# XML browsing and printing functions
+#
+
+def elm_parent(root, elm):
+    """
+    Return the parent of the element.
+    """
+    if lxml:
+        return elm.getparent()
+    else:
+        def find_parent(cur, elm):
+            for o in cur:
+                if o == elm:
+                    return cur
+                parent = find_parent(o, elm)
+                if parent is not None:
+                    return parent
+            return None
+        return find_parent(root, elm)
 
 def step_elm(elm):
     """
@@ -96,18 +336,23 @@ def errpath(filename, tree, elm):
     oid = elm.attrib.get('id')
     if oid is not None:
         oid = oid.encode('ascii','ignore').decode('ascii')
-        path += "[@id='%s']" % oid
-    if lxml:
-        elm = elm.getparent()
-        while elm is not None:
-            step = step_elm(elm)
-            path = step + path
-            elm = elm.getparent()
+        path = "//" + path + "[@id='%s']" % oid
     else:
-        path = find_elm(tree.getroot(), elm)[:-1]
+        if lxml:
+            elm = elm.getparent()
+            while elm is not None:
+                step = step_elm(elm)
+                path = step + path
+                elm = elm.getparent()
+        else:
+            path = find_elm(tree.getroot(), elm)[:-1]
     path = filename + ':' + path
     return path
 
+#
+# Warning/Error printing functions
+#
+
 def elm_prefix(filename, elm):
     """
     Return the display prefix of the element
@@ -128,10 +373,49 @@ def elm_name(elm):
         if 'id' in elm.attrib:
             id = elm.attrib['id'].encode('ascii','ignore').decode('ascii')
             name += "'%s' " % id
+        if not name:
+            name = "'" + elm.tag + "'"
+            if lxml:
+                name += " line " + str(elm.sourceline)
         return name
     return ""
 
-def elm_suppr(filename, tree, elm, msgtype):
+def elm_name_line(elm):
+    """
+    Return a display name of the element with line number
+    """
+    if elm is not None:
+        name = elm_name(elm)
+        if lxml and " line " not in name:
+            name += "line " + str(elm.sourceline) + " "
+        return name
+    return ""
+
+def elm_line(elm):
+    """
+    Return the line for the given element.
+    """
+    if lxml:
+        return " line " + str(elm.sourceline)
+    else:
+        return ""
+
+def elms_lines(elms):
+    """
+    Return the list of lines for the given elements.
+    """
+    if lxml:
+        return " lines " + ', '.join([str(l.sourceline) for l in elms])
+    else:
+        return ""
+
+def elms_names_lines(elms):
+    """
+    Return the list of names and lines for the given elements.
+    """
+    return ', '.join([elm_name_line(elm) for elm in elms])
+
+def elm_suppr(filename, tree, elm, msgtype, dogen):
     """
     Return the prefix to be displayed to the user and the suppression line for
     the warning type "msgtype" for element "elm"
@@ -146,7 +430,7 @@ def elm_suppr(filename, tree, elm, msgtype):
     if suppressions or gen_suppr is not None:
         suppr = '%s %s' % (prefix, msgtype)
 
-        if gen_suppr is not None and msgtype is not None:
+        if gen_suppr is not None and msgtype is not None and dogen:
             if gen_supprfile is None:
                 gen_supprfile = open(gen_suppr, 'w')
             print(suppr, file=gen_supprfile)
@@ -161,90 +445,458 @@ def elm_suppr(filename, tree, elm, msgtype):
 
     return (prefix, suppr)
 
-def err(filename, tree, elm, msgtype, msg):
+def is_enabled(elm, msgtype, l, default):
     """
-    Emit an error for an element
+    Test whether warning type msgtype is enabled for elm in l
     """
-    global errors, errexists
-
-    (prefix, suppr) = elm_suppr(filename, tree, elm, msgtype)
-
-    if suppr in suppressions:
-        # Suppressed
-        errexists += 1
-        return
-
-    errors += 1
-    msg = "%s ERROR: %s%s" % (prefix, elm_name(elm), msg)
-    print(msg)
-    if outfile is not None:
-        print(msg, file=outfile)
-
+    enabled = default
+    for (enable, thetype, klass) in l:
+        # Match warning type
+        if thetype is not None:
+            if thetype != msgtype:
+                continue
+        # Match elm class
+        if klass is not None and elm is not None:
+            if klass != elm.attrib.get('class'):
+                continue
+        enabled = enable
+    return enabled
 
-def warn(filename, tree, elm, msgtype, msg):
+def err(filename, tree, elm, msgtype, msg, error = True):
     """
-    Emit a warning for an element
+    Emit a warning or error for an element
     """
-    global Werror, Wnone, errors, errexists, warnings, warnexists
+    global errors, errexists, warnings, warnexists, fatals, fatalexists
 
-    if Wnone:
+    # Let user tune whether a warning or error
+    fatal = is_enabled(elm, msgtype, dofatals, error)
+
+    # By default warnings and errors are enabled, but let user tune it
+    if not is_enabled(elm, msgtype, enables, True):
         return
 
-    (prefix, suppr) = elm_suppr(filename, tree, elm, msgtype)
+    (prefix, suppr) = elm_suppr(filename, tree, elm, msgtype, True)
     if suppr in suppressions:
         # Suppressed
-        if Werror:
+        suppressions[suppr] = False
+        if fatal:
+            fatalexists += 1
+        if error:
             errexists += 1
         else:
             warnexists += 1
         return
 
-    if Werror:
+    if error:
         errors += 1
     else:
         warnings += 1
+    if fatal:
+        fatals += 1
 
-    msg = "%s WARNING: %s%s" % (prefix, elm_name(elm), msg)
+    msg = "%s %s%s: %s%s" % (prefix,
+            "FATAL " if fatal else "",
+            "ERROR" if error else "WARNING",
+            elm_name(elm), msg)
     print(msg)
     if outfile is not None:
         print(msg, file=outfile)
 
+def warn(filename, tree, elm, msgtype, msg):
+    """
+    Emit a warning for an element
+    """
+    err(filename, tree, elm, msgtype, msg, False)
+
+#
+# Labelling testing functions
+#
 
-def check_objects(filename, tree, elm, objects, target):
+def find_button_parent(root, elm):
     """
-    Check that objects contains exactly one object
+    Find a parent which is a button
     """
-    length = len(list(objects))
-    if length == 0:
-        err(filename, tree, elm, "undeclared-target", "uses undeclared target '%s'" % target)
-    elif length > 1:
-        err(filename, tree, elm, "multiple-target", "several targets are named '%s'" % target)
+    if lxml:
+        parent = elm.getparent()
+        if parent is not None:
+            if parent.attrib.get('class') in widgets_buttons:
+                return parent
+            return find_button_parent(root, parent)
+    else:
+        def find_parent(cur, elm):
+            for o in cur:
+                if o == elm:
+                    if cur.attrib.get('class') in widgets_buttons:
+                        # we are the button, immediately above the target
+                        return cur
+                    else:
+                        # we aren't the button, but target is over there
+                        return True
+                parent = find_parent(o, elm)
+                if parent == True:
+                    # It is over there, but didn't find a button yet
+                    if cur.attrib.get('class') in widgets_buttons:
+                        # we are the button
+                        return cur
+                    else:
+                        return True
+                if parent is not None:
+                    # we have the button parent over there
+                    return parent
+            return None
+        parent = find_parent(root, elm)
+        if parent == True:
+            parent = None
+        return parent
+
 
-def check_props(filename, tree, root, elm, props):
+def is_labelled_parent(elm):
     """
-    Check the given list of relation properties
+    Return whether this element is a labelled parent
     """
-    for prop in props:
-        objects = root.iterfind(".//object[@id='%s']" % prop.text)
-        check_objects(filename, tree, elm, objects, prop.text)
+    klass = elm.attrib.get('class')
+    if klass in widgets_toplevel:
+        return True
+    if klass == 'GtkShortcutsGroup':
+        children = elm.findall("property[@name='title']")
+        if len(children) >= 1:
+            return True
+    if klass == 'GtkFrame' or klass == 'GtkNotebook':
+        children = elm.findall("child[@type='tab']") + elm.findall("child[@type='label']") 
+        if len(children) >= 1:
+            return True
+    return False
 
-def check_rels(filename, tree, root, elm, rels):
+def elm_labelled_parent(root, elm):
     """
-    Check the given list of relations
+    Return the first labelled parent of the element, which can thus be used as
+    the root of widgets with common labelled context
     """
-    for rel in rels:
+
+    if lxml:
+        def find_labelled_parent(elm):
+            if is_labelled_parent(elm):
+                return elm
+            parent = elm.getparent()
+            if parent is None:
+                return None
+            return find_labelled_parent(parent)
+        parent = elm.getparent()
+        if parent is None:
+            return None
+        return find_labelled_parent(elm.getparent())
+    else:
+        def find_labelled_parent(cur, elm):
+            if cur == elm:
+                # the target element is over there
+                return True
+            for o in cur:
+                parent = find_labelled_parent(o, elm)
+                if parent == True:
+                    # target element is over there, check ourself
+                    if is_labelled_parent(cur):
+                        # yes, and we are the first ancestor of the target element
+                        return cur
+                    else:
+                        # no, but target element is over there.
+                        return True
+                if parent != None:
+                    # the first ancestor of the target element was over there
+                    return parent
+            return None
+        parent = find_labelled_parent(root, elm)
+        if parent == True:
+            parent = None
+        return parent
+
+def is_orphan_label(filename, tree, root, obj, orphan_root, doprint = False):
+    """
+    Check whether this label has no accessibility relation, or doubtful relation
+    because another label labels the same target
+    """
+    global label_for_elm, labelled_by_elm, mnemonic_for_elm, warnexists
+
+    # label-for
+    label_for = obj.findall("accessibility/relation[@type='label-for']")
+    for rel in label_for:
         target = rel.attrib['target']
-        targets = root.iterfind(".//object[@id='%s']" % target)
-        check_objects(filename, tree, elm, targets, target)
+        l = label_for_elm[target]
+        if len(l) > 1:
+            return True
 
-def elms_lines(elms):
+    # mnemonic_widget
+    mnemonic_for = obj.findall("property[@name='mnemonic_widget']")
+    for rel in mnemonic_for:
+        target = rel.text
+        l = mnemonic_for_elm[target]
+        if len(l) > 1:
+            return True
+
+    if len(label_for) > 0:
+        # At least one label-for, we are not orphan.
+        return False
+
+    if len(mnemonic_for) > 0:
+        # At least one mnemonic_widget, we are not orphan.
+        return False
+
+    labelled_by = obj.findall("accessibility/relation[@type='labelled-by']")
+    if len(labelled_by) > 0:
+        # Oh, a labelled label, probably not to be labelling anything
+        return False
+
+    parent = elm_parent(root, obj)
+    if parent is not None:
+        childtype = parent.attrib.get('type')
+        if childtype is None:
+            childtype = parent.attrib.get('internal-child')
+        if parent.tag == 'child' and childtype == 'label' \
+                                  or childtype == 'tab':
+            # This is a frame or a notebook label, not orphan.
+            return False
+
+    if find_button_parent(root, obj) is not None:
+        # This label is part of a button
+        return False
+
+    oid = obj.attrib.get('oid')
+    if oid is not None:
+        if oid in labelled_by_elm:
+            # Some widget is labelled by us, we are not orphan.
+            # We should have had a label-for, will warn about it later.
+            return False
+
+    # No label-for, no mnemonic-for, no labelled-by, we are orphan.
+    (_, suppr) = elm_suppr(filename, tree, obj, "orphan-label", False)
+    if suppr in suppressions:
+        # Warning suppressed for this label
+        if suppressions[suppr]:
+            warnexists += 1
+        suppressions[suppr] = False
+        return False
+
+    if doprint:
+        context = elm_name(orphan_root)
+        if context:
+            context = " within " + context
+        warn(filename, tree, obj, "orphan-label", "does not specify what it labels" + context)
+    return True
+
+def is_orphan_widget(filename, tree, root, obj, orphan, orphan_root, doprint = False):
     """
-    Return the list of lines for the given elements.
+    Check whether this widget has no accessibility relation.
     """
-    if lxml:
-        return ": lines " + ', '.join([str(l.sourceline) for l in elms])
+    global warnexists
+    if obj.tag != 'object':
+        return False
+
+    oid = obj.attrib.get('id')
+    klass = obj.attrib.get('class')
+
+    # "Don't care" special case
+    if klass in widgets_ignored:
+        return False
+    for suffix in widgets_suffixignored:
+        if klass[-len(suffix):] == suffix:
+            return False
+
+    # Widgets usual do not strictly require a label, i.e. a labelled parent
+    # is enough for context, but some do always need one.
+    requires_label = klass in widgets_needlabel
+
+    labelled_by = obj.findall("accessibility/relation[@type='labelled-by']")
+
+    # Labels special case
+    if klass in widgets_labels:
+        return False
+
+    # Case 1: has an explicit <child internal-child="accessible"> sub-element
+    children = obj.findall("child[@internal-child='accessible']")
+    if len(children) > 1 and doprint:
+        err(filename, tree, obj, "multiple-accessible", "has multiple <child internal-child='accessible'>"
+            "%s" % elms_lines(children))
+    if len(children) >= 1:
+        return False
+
+    # Case 2: has an <accessibility> sub-element with a "labelled-by"
+    # <relation> pointing to an existing element.
+    if len(labelled_by) > 0:
+        return False
+
+    # Case 3: has a label-for
+    if oid in label_for_elm:
+        return False
+
+    # Case 4: has a mnemonic
+    if oid in mnemonic_for_elm:
+        return False
+
+    # Case 5: Has a <property name="tooltip_text">
+    tooltips = obj.findall("property[@name='tooltip_text']")
+    if len(tooltips) > 1 and doprint:
+        err(filename, tree, obj, "multiple-tooltip", "has multiple tooltip_text properties")
+    if len(tooltips) >= 1:
+        return False
+
+    # Case 6: Has a <property name="placeholder_text">
+    placeholders = obj.findall("property[@name='placeholder_text']")
+    if len(placeholders) > 1 and doprint:
+        err(filename, tree, obj, "multiple-placeholder", "has multiple placeholder_text properties")
+    if len(placeholders) >= 1:
+        return False
+
+    # Buttons usually don't need an external label, their own is enough, (but they do need one)
+    if klass in widgets_buttons:
+
+        labels = obj.findall("property[@name='label']")
+        if len(labels) > 1 and doprint:
+            err(filename, tree, obj, "multiple-label", "has multiple label properties")
+        if len(labels) >= 1:
+            # Has a <property name="label">
+            return False
+
+        actions = obj.findall("property[@name='action_name']")
+        if len(actions) > 1 and doprint:
+            err(filename, tree, obj, "multiple-action_name", "has multiple action_name properties")
+        if len(actions) >= 1:
+            # Has a <property name="action_name">
+            return False
+
+        gtklabels = obj.findall(".//object[@class='GtkLabel']") + obj.findall(".//object[@class='GtkAccelLabel']")
+        if len(gtklabels) >= 1:
+            # Has a custom label
+            return False
+
+        # no label for a button, warn
+        if doprint:
+            warn(filename, tree, obj, "button-no-label", "does not have its own label");
+        if not is_enabled(obj, "button-no-label", enables, True):
+            # Warnings disabled
+            return False
+        (_, suppr) = elm_suppr(filename, tree, obj, "button-no-label", False)
+        if suppr in suppressions:
+            # Warning suppressed for this widget
+            if suppressions[suppr]:
+                warnexists += 1
+            suppressions[suppr] = False
+            return False
+        return True
+
+    # GtkImages special case
+    if klass == "GtkImage":
+        uses = [u for u in tree.iterfind(".//object/property[@name='image']") if u.text == oid]
+        if len(uses) > 0:
+            # This image is just used by another element, don't warn
+            # about the image itself, we probably want the warning on
+            # the element instead.
+            return False
+
+        if find_button_parent(root, obj) is not None:
+            # This image is part of a button, we want the warning on the button
+            # instead, if any.
+            return False
+
+    # GtkEntry special case
+    if klass == 'GtkEntry' or klass == 'GtkSearchEntry':
+        parent = elm_parent(root, obj)
+        if parent is not None:
+            if parent.tag == 'child' and \
+                parent.attrib.get('internal-child') == "entry":
+                # This is an internal entry of another widget. Relations
+                # will be handled by that widget.
+                return False
+
+    # GtkShortcutsShortcut special case
+    if klass == 'GtkShortcutsShortcut':
+        children = obj.findall("property[@name='title']")
+        if len(children) >= 1:
+            return False
+
+
+    # Really no label, perhaps emit a warning
+    if not is_enabled(obj, "no-labelled-by", enables, True):
+        # Warnings disabled for this class of widgets
+        return False
+    (_, suppr) = elm_suppr(filename, tree, obj, "no-labelled-by", False)
+    if suppr in suppressions:
+        # Warning suppressed for this widget
+        if suppressions[suppr]:
+            warnexists += 1
+        suppressions[suppr] = False
+        return False
+
+    if not orphan:
+        # No orphan label, so probably the labelled parent provides enough
+        # context.
+        if requires_label:
+            # But these always need a label.
+            if doprint:
+                warn(filename, tree, obj, "no-labelled-by", "has no accessibility label")
+            return True
+        return False
+
+    if doprint:
+        context = elm_name(orphan_root)
+        if context:
+            context = " within " + context
+        warn(filename, tree, obj, "no-labelled-by", "has no accessibility label while there are orphan labels" + context)
+    return True
+
+def orphan_items(filename, tree, root, elm):
+    """
+    Check whether from some element there exists orphan labels and orphan widgets
+    """
+    orphan_labels = False
+    orphan_widgets = False
+    if elm.attrib.get('class') in widgets_labels:
+        orphan_labels = is_orphan_label(filename, tree, root, elm, None)
     else:
-        return ""
+        orphan_widgets = is_orphan_widget(filename, tree, root, elm, True, None)
+    for obj in elm:
+        # We are not interested in orphan labels under another labelled
+        # parent.  This also allows to keep linear complexity.
+        if not is_labelled_parent(obj):
+            label, widget = orphan_items(filename, tree, root, obj)
+            if label:
+                orphan_labels = True
+            if widget:
+                orphan_widgets = True
+            if orphan_labels and orphan_widgets:
+                # No need to look up more
+                break
+    return orphan_labels, orphan_widgets
+
+#
+# UI accessibility checks
+#
+
+def check_props(filename, tree, root, elm, forward):
+    """
+    Check the given list of relation properties
+    """
+    props = elm.findall("property[@name='mnemonic_widget']")
+    for prop in props:
+        if prop.text not in ids:
+            err(filename, tree, elm, "undeclared-target", forward + " uses undeclared target '%s'" % prop.text)
+    return props
+
+def check_rels(filename, tree, root, elm, forward, backward = None):
+    """
+    Check the relations given by forward
+    """
+    oid = elm.attrib.get('id')
+    rels = elm.findall("accessibility/relation[@type='" + forward + "']")
+    for rel in rels:
+        target = rel.attrib['target']
+        if target not in ids:
+            err(filename, tree, elm, "undeclared-target", forward + " uses undeclared target '%s'" % target)
+        elif backward is not None:
+            widget = ids[target]
+            backrels = widget.findall("accessibility/relation[@type='" + backward + "']")
+            if len([x for x in backrels if x.attrib['target'] == oid]) == 0:
+                err(filename, tree, elm, "missing-" + backward, "has " + forward + \
+                    ", but is not " + backward + " by " + elm_name_line(widget))
+    return rels
 
 def check_a11y_relation(filename, tree):
     """
@@ -252,111 +904,256 @@ def check_a11y_relation(filename, tree):
     document represented by `root' doesn't comply with Accessibility
     rules.
     """
-    root = tree.getroot()
+    global widgets_ignored, ids, label_for_elm, labelled_by_elm, mnemonic_for_elm
 
-    for obj in root.iter('object'):
+    def check_elm(orphan_root, obj, orphan_labels, orphan_widgets):
+        """
+        Check one element, knowing that orphan_labels/widgets tell whether
+        there are orphan labels and widgets within orphan_root
+        """
 
-        label_for = obj.findall("accessibility/relation[@type='label-for']")
-        check_rels(filename, tree, root, obj, label_for)
+        oid = obj.attrib.get('id')
+        klass = obj.attrib.get('class')
 
-        labelled_by = obj.findall("accessibility/relation[@type='labelled-by']")
-        check_rels(filename, tree, root, obj, labelled_by)
+        # "Don't care" special case
+        if klass in widgets_ignored:
+            return
+        for suffix in widgets_suffixignored:
+            if klass[-len(suffix):] == suffix:
+                return
 
-        member_of = obj.findall("accessibility/relation[@type='member-of']")
-        check_rels(filename, tree, root, obj, member_of)
+        # Widgets usual do not strictly require a label, i.e. a labelled parent
+        # is enough for context, but some do always need one.
+        requires_label = klass in widgets_needlabel
 
-        if obj.attrib['class'] == 'GtkLabel':
-            # Case 0: A 'GtkLabel' must contain one or more "label-for"
-            # pointing to existing elements or...
-            if len(label_for) > 0:
-                continue
+        if oid is not None:
+            # Check that ids are unique
+            if oid in ids_dup:
+                if ids[oid] == obj:
+                    # We are the first, warn
+                    duplicates = tree.findall(".//object[@id='" + oid + "']")
+                    err(filename, tree, obj, "duplicate-id", "has the same id as other elements " + elms_names_lines(duplicates))
+
+        # Check label-for and their dual labelled-by
+        label_for = check_rels(filename, tree, root, obj, "label-for", "labelled-by")
+
+        # Check labelled-by and its dual label-for
+        labelled_by = check_rels(filename, tree, root, obj, "labelled-by", "label-for")
 
-            # ...a single "mnemonic_widget"
-            properties = obj.findall("property[@name='mnemonic_widget']")
-            check_props(filename, tree, root, obj, properties)
+        # Should have only one label
+        if len(labelled_by) >= 1:
+            if oid in mnemonic_for_elm:
+                warn(filename, tree, obj, "labelled-by-and-mnemonic",
+                     "has both a mnemonic " + elm_name_line(mnemonic_for_elm[oid][0]) + "and labelled-by relation")
+            if len(labelled_by) > 1:
+                warn(filename, tree, obj, "multiple-labelled-by", "has multiple labelled-by relations")
+        if oid in label_for_elm:
+            if len(label_for_elm[oid]) > 1:
+                warn(filename, tree, obj, "duplicate-label-for", "is referenced by multiple label-for " + elms_names_lines(label_for_elm[oid]))
+        if oid in mnemonic_for_elm:
+            if len(mnemonic_for_elm[oid]) > 1:
+                warn(filename, tree, obj, "duplicate-mnemonic", "is referenced by multiple mnemonic_widget " + elms_names_lines(mnemonic_for_elm[oid]))
+
+        # Check member-of
+        member_of = check_rels(filename, tree, root, obj, "member-of")
+
+        # Labels special case
+        if klass in widgets_labels:
+            properties = check_props(filename, tree, root, obj, "mnemonic_widget")
             if len(properties) > 1:
-                # It does not make sense for a label to be a mnemonic for
-                # several actions.
-                err(filename, tree, obj, "multiple-mnemonic", "has too many sub-elements"
-                    ", expected single <property name='mnemonic_widgets'>"
+                err(filename, tree, obj, "multiple-mnemonic", "has multiple mnemonic_widgets properties"
                     "%s" % elms_lines(properties))
-                continue
-            if len(properties) == 1:
-                continue
-            # TODO: warn that it is a label for nothing
-            continue
 
-        # Case 1: has a <child internal-child="accessible"> sub-element
-        children = obj.findall("child[@internal-child='accessible']")
-        if children:
-            if len(children) > 1:
-                err(filename, tree, obj, "multiple-accessible", "has too many sub-elements"
-                    ", expected single <child internal-child='accessible'>"
-                    "%s" % elms_lines(children))
-            continue
+            # Emit orphaning warnings
+            if warn_orphan_labels or orphan_widgets:
+                is_orphan_label(filename, tree, root, obj, orphan_root, True)
 
-        # Case 2: has an <accessibility> sub-element with a "labelled-by"
-        # <relation> pointing to an existing element.
-        if len(labelled_by) > 0:
-            continue
+            # We are done with the label
+            return
 
-        # Case 3/4: has an ID...
+        # Not a label, will perhaps need one
+
+        # Emit orphaning warnings
+        is_orphan_widget(filename, tree, root, obj, orphan_labels, orphan_root, True)
+
+    root = tree.getroot()
+
+    # Flush ids and relations from previous files
+    ids = {}
+    ids_dup = {}
+    labelled_by_elm = {}
+    label_for_elm = {}
+    mnemonic_for_elm = {}
+
+    # First pass to get links into hash tables, no warning, just record duplicates
+    for obj in root.iter('object'):
         oid = obj.attrib.get('id')
         if oid is not None:
-            # ...referenced by a single "label-for" <relation>
-            rels = root.iterfind(".//relation[@target='%s']" % oid)
-            labelfor = [r for r in rels if r.attrib.get('type') == 'label-for']
-            if len(labelfor) == 1:
-                continue
-            if len(labelfor) > 1:
-                err(filename, tree, obj, "multiple-label-for", "has too many elements"
-                    ", expected single <relation type='label-for' target='%s'>"
-                    "%s" % (oid, elm_lines(labelfor)))
-                continue
+            if oid not in ids:
+                ids[oid] = obj
+            else:
+                ids_dup[oid] = True
 
-            # ...referenced by a single "mnemonic_widget"
-            props = root.iterfind(".//property[@name='mnemonic_widget']")
-            props = [p for p in props if p.text == oid]
-            # TODO: warn when more than one.
-            if len(props) >= 1:
-                continue
+        labelled_by = obj.findall("accessibility/relation[@type='labelled-by']")
+        for rel in labelled_by:
+            target = rel.attrib.get('target')
+            if target is not None:
+                if target not in labelled_by_elm:
+                    labelled_by_elm[target] = [ obj ]
+                else:
+                    labelled_by_elm[target].append(obj)
+
+        label_for = obj.findall("accessibility/relation[@type='label-for']")
+        for rel in label_for:
+            target = rel.attrib.get('target')
+            if target is not None:
+                if target not in label_for_elm:
+                    label_for_elm[target] = [ obj ]
+                else:
+                    label_for_elm[target].append(obj)
+
+        mnemonic_for = obj.findall("property[@name='mnemonic_widget']")
+        for rel in mnemonic_for:
+            target = rel.text
+            if target is not None:
+                if target not in mnemonic_for_elm:
+                    mnemonic_for_elm[target] = [ obj ]
+                else:
+                    mnemonic_for_elm[target].append(obj)
+
+    # Second pass, recursive depth-first, to be able to efficiently know whether
+    # there are orphan labels within a part of the tree.
+    def recurse(orphan_root, obj, orphan_labels, orphan_widgets):
+        if obj == root or is_labelled_parent(obj):
+            orphan_root = obj
+            orphan_labels, orphan_widgets = orphan_items(filename, tree, root, obj)
 
-        # TODO: after a few more checks and false-positives filtering, warn
-        # that this does not have a label
-        if obj.attrib['class'] == "GtkScale":
-            # GtkScale definitely needs a context
-            err(filename, tree, obj, "no-labelled-by", "has no accessibility label")
+        if obj.tag == 'object':
+            check_elm(orphan_root, obj, orphan_labels, orphan_widgets)
 
+        for o in obj:
+            recurse(orphan_root, o, orphan_labels, orphan_widgets)
+
+    recurse(root, root, False, False)
+
+#
+# Main
+#
 
 def usage():
-    print("%s [-W error|none] [-p] [-g SUPPR_FILE] [-s SUPPR_FILE] [-P SUPPR_PREFIX] [-o LOG_FILE] [file ... | -L filelist]" % progname,
+    print("%s [-p] [-g SUPPR_FILE] [-s SUPPR_FILE] [-i WIDGET1,WIDGET2[,...]] [-o LOG_FILE] [file ...]" % progname,
           file=sys.stderr)
-    print("  -p print XML class path instead of line number");
-    print("  -g Generate suppression file SUPPR_FILE");
-    print("  -s Suppress warnings given by file SUPPR_FILE");
-    print("  -P Suppress SUPPR_PREFIX from emitted warnings, e.g. absolute source directory");
-    print("  -o Also prints errors and warnings to given file");
+    print("")
+    print("  -p Print XML class path instead of line number")
+    print("  -g Generate suppression file SUPPR_FILE")
+    print("  -s Suppress warnings given by file SUPPR_FILE")
+    print("  -i Ignore warnings for widgets of a given class")
+    print("  -o Also prints errors and warnings to given file")
+    print("")
+    print("  --widgets-FOO [+][CLASS1[,CLASS2[,...]]]")
+    print("    Give or extend one of the lists of widget classes, where FOO can be:")
+    print("    - toplevel      : widgets to be considered toplevel windows")
+    print("    - ignored       : widgets which do not need labelling (e.g. GtkBox)")
+    print("    - suffixignored : suffixes of widget classes which do not need labelling")
+    print("    - needlabel     : widgets which always need labelling (e.g. GtkEntry)")
+    print("    - buttons       : widgets which need their own label but not more")
+    print("                      (e.g. GtkButton)")
+    print("    - labels        : widgets which provide labels (e.g. GtkLabel)")
+    print("  --widgets-print print default widgets lists")
+    print("")
+    print("  --enable-all         enable all warnings/dofatals (default)")
+    print("  --disable-all        disable all warnings/dofatals")
+    print("  --fatal-all          make all warnings dofatals")
+    print("  --not-fatal-all      do not make all warnings dofatals (default)")
+    print("")
+    print("  --enable-type=TYPE    enable warning/fatal type TYPE")
+    print("  --disable-type=TYPE   disable warning/fatal type TYPE")
+    print("  --fatal-type=TYPE     make warning type TYPE an fatal")
+    print("  --not-fatal-type=TYPE make warning type TYPE not an fatal")
+    print("")
+    print("  --enable-widgets=CLASS    enable warning/fatal type CLASS")
+    print("  --disable-widgets=CLASS   disable warning/fatal type CLASS")
+    print("  --fatal-widgets=CLASS     make warning type CLASS an fatal")
+    print("  --not-fatal-widgets=CLASS make warning type CLASS not an fatal")
+    print("")
+    print("  --enable-specific=TYPE.CLASS    enable warning/fatal type TYPE for widget")
+    print("                                  class CLASS")
+    print("  --disable-specific=TYPE.CLASS   disable warning/fatal type TYPE for widget")
+    print("                                  class CLASS")
+    print("  --fatal-specific=TYPE.CLASS     make warning type TYPE an fatal for widget")
+    print("                                  class CLASS")
+    print("  --not-fatal-specific=TYPE.CLASS make warning type TYPE not an fatal for widget")
+    print("                                  class CLASS")
+    print("")
+    print("  --disable-orphan-labels         only warn about orphan labels when there are")
+    print("                                  orphan widgets in the same context")
     sys.exit(2)
 
+def widgets_opt(widgets_list, arg):
+    """
+    Replace or extend `widgets_list' with the list of classes contained in `arg'
+    """
+    append = arg and arg[0] == '+'
+    if append:
+        arg = arg[1:]
+
+    if arg:
+        widgets = arg.split(',')
+    else:
+        widgets = []
+
+    if not append:
+        del widgets_list[:]
+
+    widgets_list.extend(widgets)
+
 
 def main():
-    global pflag, Werror, Wnone, gen_suppr, gen_supprfile, suppressions, suppr_prefix, errors, outfile
+    global pflag, gen_suppr, gen_supprfile, suppressions, suppr_prefix, dofatals, enables, dofatals, warn_orphan_labels
+    global widgets_toplevel, widgets_ignored, widgets_suffixignored, widgets_needlabel, widgets_buttons, widgets_labels
+    global outfile
 
     try:
-        opts, args = getopt.getopt(sys.argv[1:], "W:pg:s:P:o:L:")
+        opts, args = getopt.getopt(sys.argv[1:], "piIg:s:P:o:L:", [
+                "widgets-toplevel=",
+                "widgets-ignored=",
+                "widgets-suffixignored=",
+                "widgets-needlabel=",
+                "widgets-buttons=",
+                "widgets-labels=",
+                "widgets-print",
+
+                "enable-all",
+                "disable-all",
+                "fatal-all",
+                "not-fatal-all",
+
+                "enable-type=",
+                "disable-type=",
+                "fatal-type=",
+                "not-fatal-type=",
+
+                "enable-widgets=",
+                "disable-widgets=",
+                "fatal-widgets=",
+                "not-fatal-widgets=",
+
+                "enable-specific=",
+                "disable-specific=",
+                "fatal-specific=",
+                "not-fatal-specific=",
+
+                "disable-orphan-labels",
+            ] )
     except getopt.GetoptError:
         usage()
 
     suppr = None
     out = None
     filelist = None
+
     for o, a in opts:
-        if o == "-W":
-            if a == "error":
-                Werror = True
-            elif a == "none":
-                Wnone = True
-        elif o == "-p":
+        if o == "-p":
             pflag = True
         elif o == "-g":
             gen_suppr = a
@@ -369,6 +1166,70 @@ def main():
         elif o == "-L":
             filelist = a
 
+        elif o == "--widgets-toplevel":
+            widgets_opt(widgets_toplevel, a)
+        elif o == "--widgets-ignored":
+            widgets_opt(widgets_ignored, a)
+        elif o == "--widgets-suffixignored":
+            widgets_opt(widgets_suffixignored, a)
+        elif o == "--widgets-needlabel":
+            widgets_opt(widgets_needlabel, a)
+        elif o == "--widgets-buttons":
+            widgets_opt(widgets_buttons, a)
+        elif o == "--widgets-labels":
+            widgets_opt(widgets_labels, a)
+        elif o == "--widgets-print":
+            print("--widgets-toplevel '" + ','.join(widgets_toplevel) + "'")
+            print("--widgets-ignored '" + ','.join(widgets_ignored) + "'")
+            print("--widgets-suffixignored '" + ','.join(widgets_suffixignored) + "'")
+            print("--widgets-needlabel '" + ','.join(widgets_needlabel) + "'")
+            print("--widgets-buttons '" + ','.join(widgets_buttons) + "'")
+            print("--widgets-labels '" + ','.join(widgets_labels) + "'")
+            sys.exit(0)
+
+        elif o == '--enable-all':
+            enables.append( (True, None, None) )
+        elif o == '--disable-all':
+            enables.append( (False, None, None) )
+        elif o == '--fatal-all':
+            dofatals.append( (True, None, None) )
+        elif o == '--not-fatal-all':
+            dofatals.append( (False, None, None) )
+
+        elif o == '--enable-type':
+            enables.append( (True, a, None) )
+        elif o == '--disable-type':
+            enables.append( (False, a, None) )
+        elif o == '--fatal-type':
+            dofatals.append( (True, a, None) )
+        elif o == '--not-fatal-type':
+            dofatals.append( (False, a, None) )
+
+        elif o == '--enable-widgets':
+            enables.append( (True, None, a) )
+        elif o == '--disable-widgets':
+            enables.append( (False, None, a) )
+        elif o == '--fatal-widgets':
+            dofatals.append( (True, None, a) )
+        elif o == '--not-fatal-widgets':
+            dofatals.append( (False, None, a) )
+
+        elif o == '--enable-specific':
+            (thetype, klass) = a.split('.', 1)
+            enables.append( (True, thetype, klass) )
+        elif o == '--disable-specific':
+            (thetype, klass) = a.split('.', 1)
+            enables.append( (False, thetype, klass) )
+        elif o == '--fatal-specific':
+            (thetype, klass) = a.split('.', 1)
+            dofatals.append( (True, thetype, klass) )
+        elif o == '--not-fatal-specific':
+            (thetype, klass) = a.split('.', 1)
+            dofatals.append( (False, thetype, klass) )
+
+        elif o == '--disable-orphan-labels':
+            warn_orphan_labels = False
+
     # Read suppression file before overwriting it
     if suppr is not None:
         try:
@@ -418,17 +1279,31 @@ def main():
         print(estr)
 
     if warnings > 0 or warnexists > 0:
-        wstr = "%s new warning%s" % (warnings,
-                                           's' if warnings > 1 else '')
+        wstr = "%s new warning%s" % (warnings, 's' if warnings > 1 else '')
         if warnexists > 0:
             wstr += " (%s suppressed by %s)" % (warnexists, suppr)
         print(wstr)
 
+    if fatals > 0 or fatalexists > 0:
+        wstr = "%s new fatal%s" % (fatals, 's' if fatals > 1 else '')
+        if fatalexists > 0:
+            wstr += " (%s suppressed by %s)" % (fatalexists, suppr)
+        print(wstr)
+
+    n = 0
+    for (suppr,unused) in suppressions.items():
+        if unused:
+            n += 1
+
+    if n > 0:
+        print("%s suppression%s unused" % (n, 's' if n > 1 else ''))
+
     if gen_supprfile is not None:
         gen_supprfile.close()
     if outfile is not None:
         outfile.close()
-    if errors > 0 and gen_suppr is None:
+    if fatals > 0 and gen_suppr is None:
+        print("Explanations are available on https://wiki.documentfoundation.org/Development/Accessibility")
         sys.exit(1)
 
 
diff --git a/solenv/gbuild/UIConfig.mk b/solenv/gbuild/UIConfig.mk
index 9a88ffd44498..fb3d82d0b912 100644
--- a/solenv/gbuild/UIConfig.mk
+++ b/solenv/gbuild/UIConfig.mk
@@ -125,11 +125,76 @@ $(call gb_UIConfig_get_clean_target,%) :
 	$(call gb_Output_announce,$*,$(false),UIA,2)
 	rm -f $(call gb_UIConfig_get_a11yerrors_target,$*)
 
+gb_UIConfig_gla11y_PARAMETERS = -P $(SRCDIR)/
+
+# Disable this to see suppressed warnings
+ifeq (1,1)
+gb_UIConfig_gla11y_PARAMETERS += -s $(UI_A11YSUPPRS)
+endif
 # Enable this to regenerate suppression files
 ifeq (1,0)
-GEN_A11Y_SUPPRS = -g $(UI_A11YSUPPRS)
+gb_UIConfig_gla11y_PARAMETERS += -g $(UI_A11YSUPPRS)
 endif
 
+# Tell gla11y about LO-specific widgets
+# These are already automatically labelled Shrink/Expand
+gb_UIConfig_gla11y_PARAMETERS += --widgets-ignored +foruilo-RefButton
+# These, however, do need a label like a GtkEntry
+gb_UIConfig_gla11y_PARAMETERS += --widgets-needlabel +foruilo-RefEdit
+# These are storage, containers, or preview
+gb_UIConfig_gla11y_PARAMETERS += --widgets-suffixignored +ValueSet,HBox,VBox,ToolBox,Preview,PreviewWin,PreviewWindow,PrevWindow
+# These are buttons, thus already contain their label (but an image is not enough)
+gb_UIConfig_gla11y_PARAMETERS += --widgets-button +vcllo-SmallButton,cuilo-RubyRadioButton,chartcontrollerlo-LightButton,svtlo-ManagedMenuButton
+
+# All new warnings should be fatal except a few kinds which could be only doubtful
+gb_UIConfig_gla11y_PARAMETERS += --fatal-all --not-fatal-type duplicate-mnemonic --not-fatal-type labelled-by-and-mnemonic --not-fatal-type orphan-label
+
+# Disable all warnings types by default for now, to enable warnings types progressively
+gb_UIConfig_gla11y_PARAMETERS += --disable-all
+
+# For now, ignore orphan labels without an unlabelled widget
+gb_UIConfig_gla11y_PARAMETERS += --disable-orphan-labels
+# but do not ignore orphan labels with an unlabelled widget
+gb_UIConfig_gla11y_PARAMETERS += --enable-type orphan-label
+
+# The following are to be uncommented progressively
+
+# These are definite errors
+gb_UIConfig_gla11y_PARAMETERS += --enable-type undeclared-target
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type missing-label-for
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type missing-labelled-by
+
+# These are often buttons with only an image
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type button-no-label
+# These are often doubtful
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type duplicate-mnemonic --enable-type labelled-by-and-mnemonic
+
+# For now, disable warning about widgets without a label by default, to enable warnings for classes progressively
+# To be uncommented progressively
+gb_UIConfig_gla11y_PARAMETERS += --disable-type no-labelled-by
+# Clearly need labelling
+gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkScale
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkEntry
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkSpinButton
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkSpinner
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkProgressBar
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.svxcorelo-SvxColorListBox
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.svxcorelo-SvxLanguageBox
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.sfxlo-SvxCharView
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.foruilo-RefEdit
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.svxcorelo-PaperSizeListBox
+# Probably need labelling
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkComboBox
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkComboBoxText
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkMenuItem
+# Possibly need labelling
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkTreeView
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkTreeViewColumn
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkTextView
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkDrawingArea
+# Perhaps need labelling
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkImage
+
 define gb_UIConfig_a11yerrors__command
 $(call gb_Output_announce,$(2),$(true),UIA,1)
 $(call gb_UIConfig__gla11y_command)
diff --git a/solenv/gbuild/platform/com_GCC_class.mk b/solenv/gbuild/platform/com_GCC_class.mk
index 6d5393d2fad9..4c3531934d5e 100644
--- a/solenv/gbuild/platform/com_GCC_class.mk
+++ b/solenv/gbuild/platform/com_GCC_class.mk
@@ -159,7 +159,7 @@ define gb_UIConfig__gla11y_command
 $(call gb_Helper_abbreviate_dirs,\
 	$(gb_UIConfig_LXML_PATH) $(gb_Helper_set_ld_path) \
 	$(call gb_ExternalExecutable_get_command,python) \
-	$(gb_UIConfig_gla11y_SCRIPT) -s $(UI_A11YSUPPRS) $(GEN_A11Y_SUPPRS) -P $(SRCDIR)/ -o $@ $(UIFILES)
+	$(gb_UIConfig_gla11y_SCRIPT) $(gb_UIConfig_gla11y_PARAMETERS) -o $@ $(UIFILES)
 )
 
 endef
diff --git a/solenv/gbuild/platform/com_MSC_class.mk b/solenv/gbuild/platform/com_MSC_class.mk
index 0a1cdab314ac..8c0a23e9bf03 100644
--- a/solenv/gbuild/platform/com_MSC_class.mk
+++ b/solenv/gbuild/platform/com_MSC_class.mk
@@ -583,7 +583,7 @@ $(call gb_Helper_abbreviate_dirs,\
 	FILES=$(call var2file,$(shell $(gb_MKTEMP)),100,$(UIFILES)) && \
 	$(gb_UIConfig_LXML_PATH) $(gb_Helper_set_ld_path) \
 	$(call gb_ExternalExecutable_get_command,python) \
-	$(gb_UIConfig_gla11y_SCRIPT) -s $(UI_A11YSUPPRS) $(GEN_A11Y_SUPPRS) -P $(SRCDIR)/ -o $@ -L $$FILES
+	$(gb_UIConfig_gla11y_SCRIPT) $(gb_UIConfig_gla11y_PARAMETERS) -o $@ -L $$FILES
 )
 
 endef
diff --git a/solenv/sanitizers/ui/cui.suppr b/solenv/sanitizers/ui/cui.suppr
index d9e0294f464f..598c7a600ae3 100644
--- a/solenv/sanitizers/ui/cui.suppr
+++ b/solenv/sanitizers/ui/cui.suppr
@@ -1,3 +1,8 @@
-cui/uiconfig/ui/gradientpage.ui:GtkBox[@id='GradientPage']/GtkFrame[@id='frame1']/GtkAlignment[@id='alignment1']/GtkBox[@id='box2']/GtkGrid[@id='grid6']/GtkScale[@id='incrementslider'] no-labelled-by
-cui/uiconfig/ui/gradientpage.ui:GtkBox[@id='GradientPage']/GtkFrame[@id='frame1']/GtkAlignment[@id='alignment1']/GtkBox[@id='box2']/GtkGrid[@id='grid3']/GtkScale[@id='borderslider'] no-labelled-by
-cui/uiconfig/ui/hatchpage.ui:GtkBox[@id='HatchPage']/GtkFrame[@id='frame1']/GtkAlignment[@id='alignment1']/GtkBox[@id='box3']/GtkBox[@id='box1']/GtkScale[@id='angleslider'] no-labelled-by
+cui/uiconfig/ui/gradientpage.ui://GtkScale[@id='incrementslider'] no-labelled-by
+cui/uiconfig/ui/gradientpage.ui://GtkLabel[@id='centerft'] orphan-label
+cui/uiconfig/ui/gradientpage.ui://GtkScale[@id='borderslider'] no-labelled-by
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='distanceft'] orphan-label
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='angleft'] orphan-label
+cui/uiconfig/ui/hatchpage.ui://GtkScale[@id='angleslider'] no-labelled-by
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='linetypeft'] orphan-label
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='linecolorft'] orphan-label
diff --git a/solenv/sanitizers/ui/svt.suppr b/solenv/sanitizers/ui/svt.suppr
index 40ba68b7b93a..64325dcb38dd 100644
--- a/solenv/sanitizers/ui/svt.suppr
+++ b/solenv/sanitizers/ui/svt.suppr
@@ -1,2 +1,2 @@
-svtools/uiconfig/ui/graphicexport.ui:GtkDialog[@id='GraphicExportDialog']/GtkBox[@id='dialog-vbox1']/GtkBox[@id='box1']/GtkFrame[@id='jpgquality']/GtkAlignment[@id='alignment5']/GtkGrid[@id='grid2']/GtkScale[@id='compressionjpgsb'] no-labelled-by
-svtools/uiconfig/ui/graphicexport.ui:GtkDialog[@id='GraphicExportDialog']/GtkBox[@id='dialog-vbox1']/GtkBox[@id='box1']/GtkFrame[@id='pngcompression']/GtkAlignment[@id='alignment13']/GtkGrid[@id='grid9']/GtkScale[@id='compressionpngsb'] no-labelled-by
+svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionjpgsb'] no-labelled-by
+svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionpngsb'] no-labelled-by
diff --git a/solenv/sanitizers/ui/svx.suppr b/solenv/sanitizers/ui/svx.suppr
index 9179abb2dbd5..b9babb1171ab 100644
--- a/solenv/sanitizers/ui/svx.suppr
+++ b/solenv/sanitizers/ui/svx.suppr
@@ -1,6 +1,12 @@
-svx/uiconfig/ui/compressgraphicdialog.ui:GtkDialog[@id='CompressGraphicDialog']/GtkBox[@id='dialog-vbox1']/GtkGrid/GtkFrame[@id='frame2']/GtkAlignment[@id='alignment1']/GtkGrid[@id='grid2']/GtkAlignment/GtkGrid/GtkScale[@id='scale-quality'] no-labelled-by
-svx/uiconfig/ui/compressgraphicdialog.ui:GtkDialog[@id='CompressGraphicDialog']/GtkBox[@id='dialog-vbox1']/GtkGrid/GtkFrame[@id='frame2']/GtkAlignment[@id='alignment1']/GtkGrid[@id='grid2']/GtkAlignment/GtkGrid/GtkScale[@id='scale-compression'] no-labelled-by
-svx/uiconfig/ui/mediaplayback.ui:GtkGrid[@id='MediaPlaybackPanel']/GtkGrid[@id='grid1']/GtkScale[@id='timeslider'] no-labelled-by
-svx/uiconfig/ui/mediaplayback.ui:GtkGrid[@id='MediaPlaybackPanel']/GtkGrid[@id='grid1']/GtkScale[@id='volumeslider'] no-labelled-by
-svx/uiconfig/ui/sidebararea.ui:GtkGrid[@id='AreaPropertyPanel']/GtkBox[@id='box1']/GtkGrid[@id='grid1']/GtkScale[@id='transparencyslider'] no-labelled-by
-svx/uiconfig/ui/sidebarshadow.ui:GtkGrid[@id='ShadowPropertyPanel']/GtkGrid[@id='grid3']/GtkBox[@id='box2']/GtkBox[@id='box1']/GtkGrid[@id='grid2']/GtkScale[@id='transparency_slider'] no-labelled-by
+svx/uiconfig/ui/compressgraphicdialog.ui://GtkScale[@id='scale-quality'] no-labelled-by
+svx/uiconfig/ui/compressgraphicdialog.ui://GtkScale[@id='scale-compression'] no-labelled-by
+svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label1'] orphan-label
+svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label2'] orphan-label
+svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label3'] orphan-label
+svx/uiconfig/ui/mediaplayback.ui://GtkScale[@id='timeslider'] no-labelled-by
+svx/uiconfig/ui/mediaplayback.ui://GtkScale[@id='volumeslider'] no-labelled-by
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='angle'] orphan-label
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='distance'] orphan-label
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='transparency_label'] orphan-label
+svx/uiconfig/ui/sidebarshadow.ui://GtkScale[@id='transparency_slider'] no-labelled-by
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='color'] orphan-label


More information about the Libreoffice-commits mailing list