Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libwacom for openSUSE:Factory checked in at 2026-10-26 09:57:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libwacom (Old) and /work/SRC/openSUSE:Factory/.libwacom.new.2252680 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libwacom" Mon Oct 26 09:57:53 2026 rev:51 rq:1392141 version:2.20.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libwacom/libwacom.changes 2026-08-24 12:02:53.900356118 +0200 +++ /work/SRC/openSUSE:Factory/.libwacom.new.2252680/libwacom.changes 2026-10-26 09:57:56.916542619 +0100 @@ -1,0 +2,13 @@ +Fri Oct 23 16:33:41 UTC 2026 - Martin Pluskal <[email protected]> + +- Update to 2.20.0: + * New devices: Lenovo Yoga 9 2-in-1 14IPH11, IdeaPad 5 + 14AHP9 and ThinkBook 14s Yoga (ISDv4 526b), Huion HS610 + (new USB PID), XP-Pen Deco SE, Gaomon S620, Ugee M808 + * tools: stay quiet when /dev/input is not present +- Bump meson floor to >= 0.58.0 and add glib >= 2.68 floor, + matching the minimums declared upstream +- Spec cleanup: drop obsolete Group tags, canonical + spec-cleaner style + +------------------------------------------------------------------- Old: ---- libwacom-2.19.1.tar.xz libwacom-2.19.1.tar.xz.sig New: ---- libwacom-2.20.0.tar.xz libwacom-2.20.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libwacom.spec ++++++ --- /var/tmp/diff_new_pack.CVjFoc/_old 2026-10-26 09:57:57.822580629 +0100 +++ /var/tmp/diff_new_pack.CVjFoc/_new 2026-10-26 09:57:57.824580713 +0100 @@ -17,28 +17,26 @@ # library version from upstream meson.build %define sover 9 - Name: libwacom -Version: 2.19.1 +Version: 2.20.0 Release: 0 Summary: Tablet description library License: HPND -Group: Development/Libraries/C and C++ URL: https://linuxwacom.github.io/ Source0: https://github.com/linuxwacom/libwacom/releases/download/libwacom-%{version}/libwacom-%{version}.tar.xz Source1: https://github.com/linuxwacom/libwacom/releases/download/libwacom-%{version}/libwacom-%{version}.tar.xz.sig # Fetched from https://github.com/whot.gpg Source2: %{name}.keyring Source99: baselibs.conf -BuildRequires: meson >= 0.57.0 +BuildRequires: doxygen BuildRequires: fdupes +BuildRequires: meson >= 0.58.0 BuildRequires: ninja BuildRequires: pkgconfig -BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(glib-2.0) >= 2.68 BuildRequires: pkgconfig(gudev-1.0) BuildRequires: pkgconfig(libevdev) >= 1.7.0 BuildRequires: pkgconfig(libxml-2.0) -BuildRequires: doxygen %description libwacom is a library to identify graphics tablets and their model-specific @@ -47,7 +45,6 @@ %package -n libwacom%{sover} Summary: Library to identify wacom tablets -Group: System/Libraries Requires: %{name}-data >= %{version} %description -n libwacom%{sover} @@ -59,7 +56,6 @@ %package data Summary: Data files for libwacom, a table identification library -Group: System/Libraries %description data libwacom is a library to identify graphics tablets and their model-specific @@ -68,7 +64,6 @@ %package tools Summary: Command-line tools for libwacom -Group: Hardware/Other Requires: python3-libevdev Requires: python3-pyudev @@ -79,7 +74,6 @@ %package devel Summary: Header files for libwacom -Group: Development/Libraries/C and C++ Requires: libwacom%{sover} = %{version} %description devel @@ -97,9 +91,11 @@ %install %meson_install +# Keep the literal shebang text below: the pattern matches upstream file +# content, it is not a path we emit (spec-cleaner macro-ifies it). sed -e 's-#!/usr/bin/env python3-#!/usr/bin/python3-g' -i %{buildroot}%{_bindir}/* find %{buildroot} -type f -name "*.la" -delete -print -%python3_fix_shebang +%{python3_fix_shebang} %fdupes %{buildroot}%{_datadir}/libwacom/layouts ++++++ libwacom-2.19.1.tar.xz -> libwacom-2.20.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/.github/workflows/check-for-sysinfo.yml new/libwacom-2.20.0/.github/workflows/check-for-sysinfo.yml --- old/libwacom-2.19.1/.github/workflows/check-for-sysinfo.yml 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/.github/workflows/check-for-sysinfo.yml 2026-09-07 08:48:53.000000000 +0200 @@ -1,6 +1,6 @@ name: "Check for sysinfo in data files" -on: [ pull_request ] +on: [ pull_request, merge_group ] permissions: contents: read @@ -9,7 +9,7 @@ checksysinfo: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - uses: tj-actions/changed-files@v46 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/.github/workflows/freebsd.yml new/libwacom-2.20.0/.github/workflows/freebsd.yml --- old/libwacom-2.19.1/.github/workflows/freebsd.yml 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/.github/workflows/freebsd.yml 2026-09-07 08:48:53.000000000 +0200 @@ -1,6 +1,6 @@ name: "FreeBSD build and test" -on: [ push, pull_request ] +on: [ push, pull_request, merge_group ] permissions: contents: read @@ -13,7 +13,7 @@ freebsd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: meson test uses: vmactions/freebsd-vm@v1 with: @@ -25,7 +25,7 @@ meson setup builddir meson test -C builddir --print-errorlogs # Capture all the meson logs, even if we failed - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: ${{ always() }} # even if we fail with: name: meson test logs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/.github/workflows/label-commenter.yml new/libwacom-2.20.0/.github/workflows/label-commenter.yml --- old/libwacom-2.19.1/.github/workflows/label-commenter.yml 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/.github/workflows/label-commenter.yml 2026-09-07 08:48:53.000000000 +0200 @@ -15,6 +15,6 @@ comment: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Label Commenter uses: peaceiris/actions-label-commenter@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/.github/workflows/main.yml new/libwacom-2.20.0/.github/workflows/main.yml --- old/libwacom-2.19.1/.github/workflows/main.yml 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/.github/workflows/main.yml 2026-09-07 08:48:53.000000000 +0200 @@ -1,6 +1,6 @@ name: "Build and test" -on: [ push, pull_request ] +on: [ push, pull_request, merge_group ] permissions: contents: read @@ -19,9 +19,9 @@ - gcc - clang steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' - uses: ./.github/actions/pkginstall @@ -44,7 +44,7 @@ with: ninja_args: dist # Capture all the meson logs, even if we failed - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: ${{ always() }} # even if we fail with: name: meson test logs-${{matrix.compiler}} ${{matrix.meson_options}} @@ -54,7 +54,7 @@ - name: move tarballs to top level run: mv builddir/meson-dist/libwacom-*tar.xz . # We only need one tarball for the build-from-tarball job - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: ${{ matrix.compiler == 'gcc' && matrix.meson_options == '' }} with: name: tarball @@ -67,9 +67,9 @@ clang-tidy: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' - uses: ./.github/actions/pkginstall @@ -91,9 +91,9 @@ valgrind: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' - uses: ./.github/actions/pkginstall @@ -113,7 +113,7 @@ env: CC: ${{matrix.compiler}} # Capture all the meson logs, even if we failed - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: ${{ always() }} # even if we fail with: name: meson test logs-valgrind @@ -141,9 +141,9 @@ - sudo csplit data/wacom.stylus '/^\[0x56a:0x822\]/' && sudo mv xx00 /etc/libwacom/first.stylus && sudo mv xx01 /usr/share/libwacom/wacom.stylus steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' # Run as sudo because we install to /etc and thus need the pip @@ -176,9 +176,9 @@ needs: build-and-dist runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' # Run as sudo because we install to /etc and thus need the pip @@ -211,8 +211,8 @@ # We expect the overridden match *not* to be listed - name: check for the expected devices to be present (or not present) run: | - test "$(libwacom-list-devices --format=yaml | yq -r '.devices[] | select(.bus == "usb") | select(.vid == "0x056a") | select(.pid == "0x032a") | .name')" == "Wacom Cintiq 27QHD MODIFIED" - test "$(libwacom-list-devices --format=yaml | yq -r '.devices[] | select(.bus == "bluetooth") | select(.vid == "0x056a") | select(.pid == "0x0361") | .name')" == "Wacom Intuos Pro L MODIFIED" + test "$(libwacom-list-devices --format=yaml | yq -r '.devices[] | select(.bus == "usb") | select(.vid == "0x056a") | select(.pid == "0x032a") | .name')" = "Wacom Cintiq 27QHD MODIFIED" + test "$(libwacom-list-devices --format=yaml | yq -r '.devices[] | select(.bus == "bluetooth") | select(.vid == "0x056a") | select(.pid == "0x0361") | .name')" = "Wacom Intuos Pro L MODIFIED" test $(libwacom-list-devices --format=yaml | yq -r '.devices[] | select(.bus == "usb") | select(.vid == "0x056a") | select(.pid == "0x0358") | .name' | wc -l) -eq 0 test $(libwacom-list-devices --format=yaml | yq -r '.devices[] | select(.bus == "usb") | select(.vid == "0x056a") | select(.pid == "0x032a") | .name' | wc -l) -eq 1 @@ -222,9 +222,9 @@ needs: build-and-dist runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' # Run as sudo because we install to /etc and thus need the pip @@ -251,8 +251,8 @@ needs: build-and-dist runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: python-version: '3.12' - name: run clean-svg on all .tablet files @@ -273,9 +273,9 @@ TARBALLDIR: '_tarball_dir' INSTALLDIR: '/tmp/libwacom/_inst' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: install python - uses: actions/setup-python@v5 + uses: actions/setup-python@v7 with: python-version: '3.12' - uses: ./.github/actions/pkginstall @@ -283,7 +283,7 @@ apt: $UBUNTU_PACKAGES pip: $PIP_PACKAGES - name: fetch tarball from previous job(s) - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: tarball - name: extract tarball diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/.github/workflows/pages.yml new/libwacom-2.20.0/.github/workflows/pages.yml --- old/libwacom-2.19.1/.github/workflows/pages.yml 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/.github/workflows/pages.yml 2026-09-07 08:48:53.000000000 +0200 @@ -18,12 +18,12 @@ permissions: contents: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: ./.github/actions/pkginstall with: apt: $UBUNTU_PACKAGES # install python so we get pip for meson - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3.12' - uses: ./.github/actions/pkginstall diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/.github/workflows/style.yml new/libwacom-2.20.0/.github/workflows/style.yml --- old/libwacom-2.19.1/.github/workflows/style.yml 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/.github/workflows/style.yml 2026-09-07 08:48:53.000000000 +0200 @@ -1,6 +1,6 @@ name: "Coding style" -on: [ push, pull_request ] +on: [ push, pull_request, merge_group ] permissions: contents: read @@ -13,8 +13,8 @@ clang-format: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: python-version: '3.12' - uses: ./.github/actions/pkginstall diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/NEWS new/libwacom-2.20.0/NEWS --- old/libwacom-2.19.1/NEWS 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/NEWS 2026-09-07 08:48:53.000000000 +0200 @@ -1,3 +1,11 @@ +libwacom 2.20.0: +- New Devices: + - Lenovo Yoga 9, IdeaPad 5, ThinkBook 14s Yoga + - Huion HS610 + - XP-Pen Deco SE + - Gaomon S620 + - Ugee M808 + libwacom 2.19.1: - Build fixes for older systems and other arches diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/gaomon-s620.tablet new/libwacom-2.20.0/data/gaomon-s620.tablet --- old/libwacom-2.19.1/data/gaomon-s620.tablet 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/data/gaomon-s620.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -11,7 +11,7 @@ [Device] Name=GAOMON S620 ModelName= -DeviceMatch=usb|256c|006d|GAOMON Gaomon Tablet Pen;usb|256c|006d|GAOMON Gaomon Tablet Pad;usb|256c|006d|GAOMON Gaomon Tablet Pen|OEM02_T18e;usb|256c|006d|GAOMON Gaomon Tablet Pad|OEM02_T18e; +DeviceMatch=usb|256c|006d|GAOMON Gaomon Tablet Pen;usb|256c|006d|GAOMON Gaomon Tablet Pad;usb|256c|006d|GAOMON Gaomon Tablet Pen|OEM02_T18e;usb|256c|006d|GAOMON Gaomon Tablet Pad|OEM02_T18e;usb|256c|006f|GAOMON Gaomon Tablet;usb|256c|006f|GAOMON Gaomon Tablet Pen Width=152 Height=102 Layout=gaomon-s620.svg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/huion-hs610.tablet new/libwacom-2.20.0/data/huion-hs610.tablet --- old/libwacom-2.19.1/data/huion-hs610.tablet 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/data/huion-hs610.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -5,7 +5,7 @@ [Device] Name=Huion HS610 ModelName=HS610 -DeviceMatch=usb|256c|0064||HUION_T194 +DeviceMatch=usb|256c|0064||HUION_T194;usb|256c|006d||HUION_T194 Width=254 Height=152 Layout=huion-hs610.svg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/layouts/ugee-m808.svg new/libwacom-2.20.0/data/layouts/ugee-m808.svg --- old/libwacom-2.19.1/data/layouts/ugee-m808.svg 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/layouts/ugee-m808.svg 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="ugee-m808" width="330" height="210" style="color:#000000;stroke:#7f7f7f;fill:none;stroke-width:.25;font-size:8" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <title id="title">ugee-m808</title> + <rect id="DrawingArea" class="DrawingArea" x="59" y="29" width="254" height="152"/> + <rect id="Outline" class="Outline" x="0" y="0" width="330" height="210" rx="29.5" ry="58"/> + <g id="g8"> + <path id="LeaderE" class="E Leader" d="M 52 104 H 70"/> + <text id="LabelE" class="E Label" x="71" y="107" style="text-anchor:start;">E</text> + </g> + <g id="g9"> + <path id="LeaderC" class="C Leader" d="M 38 90 H 70"/> + <text id="LabelC" class="C Label" x="71" y="93" style="text-anchor:start;">C</text> + </g> + <g id="g6"> + <path id="LeaderD" class="D Leader" d="m 19 108 v 21 h 50"/> + <text id="LabelD" class="D Label" x="70.5" y="132" style="text-anchor:start;">D</text> + </g> + <g id="g3"> + <circle id="Ring" class="Ring" cx="34" cy="104" r="19.5"/> + <circle id="InnerRing" class="Inner Ring" cx="34" cy="104" r="9.5"/> + <circle id="ButtonE" class="E Button" cx="48.5" cy="104" r="1"/> + <circle id="ButtonC" class="C Button" cx="34" cy="89.5" r="1"/> + <circle id="ButtonD" class="D Button" cx="19.5" cy="104" r="1"/> + <circle id="ButtonF" class="F Button" cx="34" cy="118.5" r="1"/> + </g> + <g id="g7"> + <path id="LeaderF" class="F Leader" d="M 38 118 H 70"/> + <text id="LabelF" class="F Label" x="71" y="121" style="text-anchor:start;">F</text> + </g> + <g id="g11"> + <path id="LeaderB" class="B Leader" d="M 43.5 60 V 41"/> + <text id="LabelB" class="B Label" x="41" y="39.5" style="text-anchor:start;">B</text> + </g> + <g id="ButtonA" class="A Button"> + <rect id="rect14" x="23.5" y="70.5" width="2.5" height="0.5" ry="0"/> + <circle id="path14" cx="24.5" cy="70.5" r="8"/> + </g> + <g id="ButtonB" class="B Button"> + <path id="rect18" d="m 43 69.5 c 0 0.5 0 0.5 0 1 -0.5 0 -0.5 0 -1 0 0 0 0 0.5 0 0.5 0.5 0 0.5 0 1 0 0 0.5 0 0.5 0 1 0 0 0.5 0 0.5 0 0 -0.5 0 -0.5 0 -1 0.5 0 0.5 0 1 0 0 0 0 -0.5 0 -0.5 -0.5 0 -0.5 0 -1 0 0 -0.5 0 -0.5 0 -1 0 0 -0.5 0 -0.5 0 z"/> + <ellipse id="circle14" cx="43.5" cy="70.5" rx="8" ry="8"/> + </g> + <g id="g10"> + <path id="LeaderA" class="A Leader" d="M 24.5 60 V 41"/> + <text id="LabelA" class="A Label" x="22" y="39.5" style="text-anchor:start;">A</text> + </g> + <g id="ButtonG" class="G Button"> + <rect id="rect21" x="24.5" y="140.5" width="2.5" height="0.5" ry="0"/> + <circle id="circle20" cx="26" cy="140.5" r="8"/> + </g> + <g id="ButtonH" class="H Button"> + <circle id="circle21" cx="44.5" cy="140.5" r="8"/> + <path id="path21" d="m 44 139.5 c 0 0.5 0 0.5 0 1 -0.5 0 -0.5 0 -1 0 0 0 0 0.5 0 0.5 0.5 0 0.5 0 1 0 0 0.5 0 0.5 0 1 0 0 0.5 0 0.5 0 0 -0.5 0 -0.5 0 -1 0.5 0 0.5 0 1 0 0 0 0 -0.5 0 -0.5 -0.5 0 -0.5 0 -1 0 0 -0.5 0 -0.5 0 -1 0 0 -0.5 0 -0.5 0 z"/> + </g> + <g id="g5"> + <path id="LeaderG" class="G Leader" d="M 26 170 V 151"/> + <text id="LabelG" class="G Label" x="23" y="184.5" style="text-anchor:start;">G</text> + </g> + <g id="g4"> + <path id="LeaderH" class="H Leader" d="M 44.5 170 V 151"/> + <text id="LabelH" class="H Label" x="41.5" y="184.5" style="text-anchor:start;">H</text> + </g> +</svg> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/layouts/xp-pen-deco-se.svg new/libwacom-2.20.0/data/layouts/xp-pen-deco-se.svg --- old/libwacom-2.19.1/data/layouts/xp-pen-deco-se.svg 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/layouts/xp-pen-deco-se.svg 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,46 @@ +<?xml version='1.0' encoding='ASCII'?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="color:#000000;stroke:#7f7f7f;fill:none;stroke-width:.25;font-size:8" id="xp-pen-deco-se" width="721" height="427"> + <title id="title">XP-Pen Deco SE</title> + <rect x="161" y="59" width="491" height="311"/> + <g> + <rect id="ButtonA" class="A Button" x="45" y="65" width="44" height="26"/> + <text id="LabelA" class="A Label" x="115.0" y="80" style="text-anchor:start;">A</text> + <path style="fill:none" d="M 100.0,78.0 H 107.0" id="LeaderA" class="Leader A"/> + </g> + <g> + <rect id="ButtonB" class="B Button" x="45" y="102" width="44" height="23"/> + <text id="LabelB" class="B Label" x="115.0" y="115.5" style="text-anchor:start;">B</text> + <path style="fill:none" d="M 100.0,113.5 H 107.0" id="LeaderB" class="Leader B"/> + </g> + <g> + <rect id="ButtonC" class="C Button" x="45" y="137" width="45" height="25"/> + <text id="LabelC" class="C Label" x="115.5" y="151.5" style="text-anchor:start;">C</text> + <path style="fill:none" d="M 100.5,149.5 H 107.5" id="LeaderC" class="Leader C"/> + </g> + <g> + <rect id="ButtonD" class="D Button" x="45" y="172" width="44" height="25"/> + <text id="LabelD" class="D Label" x="115.0" y="186.5" style="text-anchor:start;">D</text> + <path style="fill:none" d="M 100.0,184.5 H 107.0" id="LeaderD" class="Leader D"/> + </g> + <g> + <rect id="ButtonE" class="E Button" x="45" y="229" width="44" height="26"/> + <text id="LabelE" class="E Label" x="115.0" y="244" style="text-anchor:start;">E</text> + <path style="fill:none" d="M 100.0,242.0 H 107.0" id="LeaderE" class="Leader E"/> + </g> + <g> + <rect id="ButtonF" class="F Button" x="45" y="265" width="44" height="25"/> + <text id="LabelF" class="F Label" x="115.0" y="279.5" style="text-anchor:start;">F</text> + <path style="fill:none" d="M 100.0,277.5 H 107.0" id="LeaderF" class="Leader F"/> + </g> + <g> + <rect id="ButtonG" class="G Button" x="45" y="301" width="44" height="24"/> + <text id="LabelG" class="G Label" x="115.0" y="315" style="text-anchor:start;">G</text> + <path style="fill:none" d="M 100.0,313.0 H 107.0" id="LeaderG" class="Leader G"/> + </g> + <g> + <rect id="ButtonH" class="H Button" x="45" y="337" width="44" height="24"/> + <text id="LabelH" class="H Label" x="115.0" y="351" style="text-anchor:start;">H</text> + <path style="fill:none" d="M 100.0,349.0 H 107.0" id="LeaderH" class="Leader H"/> + </g> +</svg> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/lenovo.stylus new/libwacom-2.20.0/data/lenovo.stylus --- old/libwacom-2.19.1/data/lenovo.stylus 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/data/lenovo.stylus 2026-09-07 08:48:53.000000000 +0200 @@ -33,3 +33,12 @@ EraserType=Button Axes=Tilt;Pressure Type=Mobile + +[0x56a:0x8d15] +# Lenovo ; VID_LENOVO | 0x544b | BAT_CHRG +Name=Lenovo Yoga Pen Gen 2 (2026) +Group=isdv4-aes +Buttons=1 +EraserType=Button +Axes=Tilt;Pressure +Type=Mobile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/ugee-m808.tablet new/libwacom-2.20.0/data/ugee-m808.tablet --- old/libwacom-2.19.1/data/ugee-m808.tablet 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/ugee-m808.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,28 @@ +# Ugee +# M808 +# +# sysinfo.SRphWtpzlc.tar.gz +#https://github.com/linuxwacom/wacom-hid-descriptors/issues/641 + +[Device] +Name=UGTABLET M808 Pen +ModelName=M808 +DeviceMatch=usb|28bd|2903 +PairedIDs= +Width=254 +Height=152 +IntegratedIn= +Layout=ugee-m808.svg +Styli=@generic-no-eraser + +[Features] +Stylus=true +Reversible=true +Touch=false +TouchSwitch=false +NumRings=0 +NumStrips=0 + +[Buttons] +Left=A;B;C;D;E;F;G;H +EvdevCodes=BTN_0;BTN_1;BTN_2;BTN_3;BTN_4;BTN_5;BTN_6;BTN_7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/wacom-hid-53bb-pen.tablet new/libwacom-2.20.0/data/wacom-hid-53bb-pen.tablet --- old/libwacom-2.19.1/data/wacom-hid-53bb-pen.tablet 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/wacom-hid-53bb-pen.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,21 @@ +# Lenovo IdeaPad 5-14AHP9 +# Pen: Wacom HID 53BB Pen +# Screen: Touchscreen 14", 1920x1200 +# Features: Stylus (1 button, eraser-invert), Touchscreen +# +# sysinfo.WlvlvxLwpX.tar.gz +# https://github.com/linuxwacom/wacom-hid-descriptors/issues/636 + +[Device] +Name=Wacom HID 53BB Pen +Class=ISDV4 +DeviceMatch=i2c|056a|53bb +Width=300 +Height=190 +IntegratedIn=Display;System +Styli=@isdv4-aes; + +[Features] +Stylus=true +Touch=true +Buttons=0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/wacom-isdv4-526b.tablet new/libwacom-2.20.0/data/wacom-isdv4-526b.tablet --- old/libwacom-2.19.1/data/wacom-isdv4-526b.tablet 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/wacom-isdv4-526b.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,21 @@ +# Lenovo ThinkBook 14s Yoga ITL +# Sensor Type: AES +# Features: Touch (Integrated), Tilt +# HW Resolution: 30931 x 17399 (2540 x 2540 lpi) +# +# Manually created; copied from wacom-isdv4-526a; Tarball: sysinfo.EKNM3yvMma.tar.gz +# https://github.com/linuxwacom/wacom-hid-descriptors/issues/640 + +[Device] +Name=ISDv4 526b +ModelName= +DeviceMatch=i2c|056a|526b +Class=ISDV4 +Width=305 +Height=178 +IntegratedIn=Display;System +Styli=@isdv4-aes; + +[Features] +Stylus=true +Touch=true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/wacom-isdv4-544b.tablet new/libwacom-2.20.0/data/wacom-isdv4-544b.tablet --- old/libwacom-2.19.1/data/wacom-isdv4-544b.tablet 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/wacom-isdv4-544b.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,22 @@ +# Lenovo Yoga 9 2-in-1 14IPH11 +# Sensor Type: AES +# Features: Touch (Integrated), Tilt +# HW Resolution: 30182 x 18864 (2540 x 2540 lpi) +# +# sysinfo.EHmHQmxCz8 +# https://github.com/linuxwacom/wacom-hid-descriptors/issues/626 + +[Device] +Name=Wacom ISDv4 544b +ModelName= +DeviceMatch=i2c|056a|544b +Class=ISDV4 +Width=301 +Height=188 +IntegratedIn=Display;System +Styli=@isdv4-aes; + +[Features] +Stylus=true +Touch=true +Buttons=0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/data/xp-pen-deco-se.tablet new/libwacom-2.20.0/data/xp-pen-deco-se.tablet --- old/libwacom-2.19.1/data/xp-pen-deco-se.tablet 1970-01-01 01:00:00.000000000 +0100 +++ new/libwacom-2.20.0/data/xp-pen-deco-se.tablet 2026-09-07 08:48:53.000000000 +0200 @@ -0,0 +1,48 @@ +# XP-Pen +# Deco SE +# CT850B +# +# sysinfo.CPdD8fL4wX +# https://github.com/linuxwacom/wacom-hid-descriptors/issues/638 +# sysinfo.3HxvPMRGCU +# https://github.com/linuxwacom/wacom-hid-descriptors/issues/638 +# +# Button Map: +# (A=1, B=2, C=3, ...) +# +# *------------------------------------* +# | | +# A | | +# B | | +# C | | +# D | | +# | TABLET | +# E | | +# F | | +# G | | +# H | | +# | | +# *------------------------------------* + +[Device] +Name=XP-Pen Deco SE +ModelName=CT850B +DeviceMatch=usb|28bd|0949;bluetooth|28bd|0949; +PairedIDs= +Width=178 +Height=111 +IntegratedIn= +Layout=xp-pen-deco-se.svg +Styli=@generic-no-eraser + +[Features] +Stylus=true +Reversible=true +Touch=false +TouchSwitch=false +NumRings=0 +NumStrips=0 + +[Buttons] +Left=A;B;C;D;E;F;G;H +EvdevCodes=BTN_0;BTN_1;BTN_2;BTN_3;BTN_4;BTN_5;BTN_6;BTN_7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/meson.build new/libwacom-2.20.0/meson.build --- old/libwacom-2.19.1/meson.build 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/meson.build 2026-09-07 08:48:53.000000000 +0200 @@ -1,5 +1,5 @@ project('libwacom', 'c', - version: '2.19.1', + version: '2.20.0', license: 'HPND', default_options: [ 'c_std=gnu99', 'warning_level=2' ], meson_version: '>= 0.58.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/test/__init__.py new/libwacom-2.20.0/test/__init__.py --- old/libwacom-2.19.1/test/__init__.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/test/__init__.py 2026-09-07 08:48:53.000000000 +0200 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # This file is formatted with ruff format # # Run with pytest: @@ -20,16 +18,14 @@ # - WacomDevice, WacomDatabase, ...: pythonic wrappers around the # underlying C object. -from ctypes import c_char_p, c_char, c_int, c_uint32, c_void_p -from typing import Optional, Tuple, Type, List -from dataclasses import dataclass -from pathlib import Path - import ctypes import enum import itertools import logging - +from ctypes import c_char, c_char_p, c_int, c_uint32, c_void_p +from dataclasses import dataclass +from pathlib import Path +from typing import ClassVar logger = logging.getLogger(__name__) @@ -40,8 +36,8 @@ @dataclass class _Api: name: str - args: Tuple[Type[ctypes._SimpleCData], ...] - return_type: Optional[Type[ctypes._SimpleCData]] + args: tuple[type[ctypes._SimpleCData], ...] + return_type: type[ctypes._SimpleCData] | None @property def basename(self) -> str: @@ -61,7 +57,7 @@ class GlibC: _lib = None - _api_prototypes: List[_Api] = [ + _api_prototypes: ClassVar[list[_Api]] = [ _Api(name="free", args=(c_void_p,), return_type=None), ] @@ -127,7 +123,7 @@ cls._load() return cls - _api_prototypes: List[_Api] = [ + _api_prototypes: ClassVar[list[_Api]] = [ _Api(name="libwacom_error_new", args=(c_void_p,), return_type=c_void_p), _Api(name="libwacom_error_free", args=(c_void_p,), return_type=None), _Api(name="libwacom_error_get_code", args=(c_void_p,), return_type=c_int), @@ -329,7 +325,7 @@ ), ] - _enums: List[_Enum] = [ + _enums: ClassVar[list[_Enum]] = [ _Enum(name="WERROR_NONE", value=0), _Enum(name="WERROR_BAD_ALLOC", value=1), _Enum(name="WERROR_INVALID_PATH", value=2), @@ -439,12 +435,12 @@ setattr(self, api.basename.removeprefix("match_"), wrapper(func)) @property - def name(self) -> Optional[str]: + def name(self) -> str | None: name = self.get_name() return name.decode("utf-8") if name else None @property - def uniq(self) -> Optional[str]: + def uniq(self) -> str | None: uniq = self.get_uniq() return uniq.decode("utf-8") if uniq else None @@ -482,23 +478,23 @@ setattr(self, api.basename.removeprefix("builder_"), wrapper(func)) @property - def device_name(self) -> Optional[str]: + def device_name(self) -> str | None: return self._device_name @property - def match_name(self) -> Optional[str]: + def match_name(self) -> str | None: return self._match_name @property - def uniq(self) -> Optional[str]: + def uniq(self) -> str | None: return self._uniq @property - def bustype(self) -> Optional[WacomBustype]: + def bustype(self) -> WacomBustype | None: return self._bustype @property - def usbid(self) -> Optional[Tuple[int, int]]: + def usbid(self) -> tuple[int, int] | None: return self._usbid @bustype.setter @@ -507,7 +503,7 @@ self.set_bustype(bus.value) @usbid.setter - def usbid(self, usbid: Tuple[int, int]): + def usbid(self, usbid: tuple[int, int]): self._usbid = usbid self.set_usbid(usbid[0], usbid[1]) @@ -529,11 +525,11 @@ @classmethod def create( cls, - device_name: Optional[str] = None, - match_name: Optional[str] = None, - uniq: Optional[str] = None, - usbid: Optional[Tuple[int, int]] = None, - bus: Optional[WacomBustype] = None, + device_name: str | None = None, + match_name: str | None = None, + uniq: str | None = None, + usbid: tuple[int, int] | None = None, + bus: WacomBustype | None = None, ) -> "WacomBuilder": lib = LibWacom.instance() builder = WacomBuilder(lib.builder_new()) @@ -660,7 +656,7 @@ def eraser_type(self) -> WacomEraserType: return WacomEraserType(self.get_eraser_type()) - def get_paired_styli(self) -> List["WacomStylus"]: + def get_paired_styli(self) -> list["WacomStylus"]: lib = LibWacom.instance() paired = lib.stylus_get_paired_styli(self.stylus, None) styli = [ @@ -705,7 +701,7 @@ DIAL2_MODESWITCH = 1 << 11 @staticmethod - def modeswitch_flags() -> List["WacomDevice.ButtonFlags"]: + def modeswitch_flags() -> list["WacomDevice.ButtonFlags"]: return [ WacomDevice.ButtonFlags.RING_MODESWITCH, WacomDevice.ButtonFlags.RING2_MODESWITCH, @@ -745,12 +741,12 @@ val = getattr(lib, e.basename) setattr(self, e.basename, val) - def get_paired_device(self) -> Optional[WacomMatch]: + def get_paired_device(self) -> WacomMatch | None: lib = LibWacom.instance() match = lib.get_paired_device(self.device) return WacomMatch(match) if match else None - def get_matches(self) -> List[WacomMatch]: + def get_matches(self) -> list[WacomMatch]: lib = LibWacom.instance() matches = lib.get_matches(self.device) @@ -759,7 +755,7 @@ for m in itertools.takewhile(lambda ptr: ptr is not None, matches) ] - def get_styli(self) -> List[WacomStylus]: + def get_styli(self) -> list[WacomStylus]: lib = LibWacom.instance() styli = lib.get_styli(self.device, None) @@ -774,7 +770,7 @@ lib.destroy(self.device) @property - def paired_device(self) -> Optional[WacomMatch]: + def paired_device(self) -> WacomMatch | None: return self.get_paired_device() @property @@ -864,11 +860,11 @@ return self.get_matches() @property - def integration_flags(self) -> List[IntegrationFlags]: + def integration_flags(self) -> list[IntegrationFlags]: flags = self.get_integration_flags() return [f for f in WacomDevice.IntegrationFlags if f & flags != 0] - def button_flags(self, button: str) -> List[ButtonFlags]: + def button_flags(self, button: str) -> list[ButtonFlags]: flags = self.get_button_flag(button.encode("utf-8")) return [f for f in WacomDevice.ButtonFlags if f & flags != 0] @@ -879,11 +875,11 @@ mode = self.get_button_modeswitch_mode(button.encode("utf-8")) return WacomDevice.ModeSwitch(mode) - def button_led_group(self, button: str) -> List[ButtonFlags]: + def button_led_group(self, button: str) -> list[ButtonFlags]: return self.get_button_led_group(button.encode("utf-8")) @property - def status_leds(self) -> List["WacomStatusLed"]: + def status_leds(self) -> list["WacomStatusLed"]: nleds = c_int() leds = self.get_status_leds(ctypes.byref(nleds)) @@ -899,7 +895,7 @@ NONE = 0x0 GENERIC = 0x1 - def __init__(self, path: Optional[Path] = None): + def __init__(self, path: Path | None = None): lib = LibWacom.instance() if path is None: self.db = lib.database_new() # type: ignore @@ -926,27 +922,27 @@ lib = LibWacom.instance() lib.database_destroy(db) - def new_from_name(self, name: str) -> Optional[WacomDevice]: + def new_from_name(self, name: str) -> WacomDevice | None: device = self.libwacom_new_from_name(name.encode("utf-8"), 0) return WacomDevice(device) if device else None def new_from_path( self, path: str, fallback: Fallback = Fallback.NONE - ) -> Optional[WacomDevice]: + ) -> WacomDevice | None: device = self.libwacom_new_from_path(path.encode("utf-8"), fallback, 0) return WacomDevice(device) if device else None - def new_from_usbid(self, vid: int, pid: int) -> Optional[WacomDevice]: + def new_from_usbid(self, vid: int, pid: int) -> WacomDevice | None: device = self.libwacom_new_from_usbid(vid, pid, 0) return WacomDevice(device) if device else None def new_from_builder( self, builder: WacomBuilder, fallback: Fallback = Fallback.NONE - ) -> Optional[WacomDevice]: + ) -> WacomDevice | None: device = self.libwacom_new_from_builder(builder.builder, fallback.value, 0) return WacomDevice(device) if device else None - def list_devices(self) -> List[WacomDevice]: + def list_devices(self) -> list[WacomDevice]: devices = self.libwacom_list_devices_from_database(self.db, 0) devs = [ WacomDevice(d, destroy=False) @@ -955,7 +951,7 @@ GlibC.instance().free(devices) return devs - def list_styli(self) -> List[WacomStylus]: + def list_styli(self) -> list[WacomStylus]: styli = self.libwacom_list_styli_from_database(self.db, 0) result = [ WacomStylus(s) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/test/conftest.py new/libwacom-2.20.0/test/conftest.py --- old/libwacom-2.19.1/test/conftest.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/test/conftest.py 2026-09-07 08:48:53.000000000 +0200 @@ -1,11 +1,9 @@ -#!/usr/bin/env python3 -# # This file is formatted with ruff format -# -from pathlib import Path import logging import os +from pathlib import Path + import pytest from . import WacomDatabase diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/test/test_data_files.py new/libwacom-2.20.0/test/test_data_files.py --- old/libwacom-2.19.1/test/test_data_files.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/test/test_data_files.py 2026-09-07 08:48:53.000000000 +0200 @@ -7,7 +7,6 @@ import re from pathlib import Path - WACOM_RECEIVER_USBIDS = [ (0x56A, 0x84), ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/test/test_libwacom.py new/libwacom-2.20.0/test/test_libwacom.py --- old/libwacom-2.19.1/test/test_libwacom.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/test/test_libwacom.py 2026-09-07 08:48:53.000000000 +0200 @@ -1,14 +1,12 @@ -#!/usr/bin/env python3 -# # This file is formatted with ruff format +import ctypes +import logging +import string from configparser import ConfigParser from dataclasses import dataclass, field -import ctypes -import logging import pytest -import string from . import ( WacomAxisType, @@ -97,8 +95,9 @@ if logger.getEffectiveLevel() == logging.DEBUG: logger.debug(f"{dir}/{filename}:") - for line in open(dir / filename).readlines(): - logger.debug(f" {line.rstrip()}") + with open(dir / filename) as f: + for line in f: + logger.debug(f" {line.rstrip()}") @dataclass @@ -148,8 +147,9 @@ if logger.getEffectiveLevel() == logging.DEBUG: logger.debug(f"{filename}:") - for line in open(filename).readlines(): - logger.debug(f" {line.rstrip()}") + with open(filename) as f: + for line in f: + logger.debug(f" {line.rstrip()}") @pytest.fixture() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/test/test_svg.py new/libwacom-2.20.0/test/test_svg.py --- old/libwacom-2.19.1/test/test_svg.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/test/test_svg.py 2026-09-07 08:48:53.000000000 +0200 @@ -1,15 +1,12 @@ -#!/usr/bin/env python3 -# # Run with pytest -from typing import Optional, List -from pathlib import Path -from dataclasses import dataclass -import xml.etree - -import os import logging +import os import string +import xml.etree +from dataclasses import dataclass +from pathlib import Path + import pytest from . import WacomDatabase, WacomDevice @@ -45,7 +42,7 @@ svg: xml.etree.ElementTree is_autogenerated: bool - def has_item(self, id: str, classes: Optional[List[str]] = None): + def has_item(self, id: str, classes: list[str] | None = None): root = self.svg.getroot() nodes = root.findall(f".//*[@id='{id}']") assert nodes, f"Failed to find required element with id {id}" @@ -87,7 +84,7 @@ ] devices = sorted(devices, key=lambda d: d.name) - def filenames(devices: List[SvgDevice]) -> List[str]: + def filenames(devices: list[SvgDevice]) -> list[str]: return [Path(d.device.layout_filename).name for d in devices] if "svgdevice" in metafunc.fixturenames: @@ -130,7 +127,7 @@ ) -def has_item(root, id: str, classes: Optional[List[str]] = None): +def has_item(root, id: str, classes: list[str] | None = None): nodes = root.findall(f".//*[@id='{id}']") assert nodes, f"Failed to find required element with id {id}" assert len(nodes) == 1, f"Expected on element with id {id}, have {len(nodes)}" @@ -193,7 +190,7 @@ except AssertionError as e: if stripdevice.is_autogenerated: pytest.skip(f"Autogenerated device has errors in SVG: {e}") - raise e + raise def test_svg_dials(dialdevice): @@ -224,7 +221,7 @@ except AssertionError as e: if dialdevice.is_autogenerated: pytest.skip(f"Autogenerated device has errors in SVG: {e}") - raise e + raise def test_svg_button(buttondevice): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/test/test_udev_rules.py new/libwacom-2.20.0/test/test_udev_rules.py --- old/libwacom-2.19.1/test/test_udev_rules.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/test/test_udev_rules.py 2026-09-07 08:48:53.000000000 +0200 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # This test will only work where /dev/uinput is available. # This test will reload the hwdb and udev rules # @@ -9,13 +7,16 @@ # - check if that device has the udev properties set we expect import configparser +import logging import os +import shutil +import subprocess +import sys from pathlib import Path + import pytest -import logging -import sys -import subprocess -import shutil + +logger = logging.getLogger(__name__) @pytest.fixture(scope="session", autouse=True) @@ -42,13 +43,13 @@ subprocess.run(["systemd-hwdb", "update"], check=True) - except (IOError, FileNotFoundError, subprocess.CalledProcessError) as e: + except (OSError, FileNotFoundError, subprocess.CalledProcessError) as e: # If any of the commands above are not found (most likely the system # simply does not use systemd), just skip. - logging.critical(f"{e}") + logger.critical(f"{e}") pytest.skip(f"Skipping test: {e}") - except Exception as e: - logging.critical(f"{e}") + except Exception as e: # noqa: BLE001 + logger.critical(f"{e}") pytest.fail(f"Aborting test: {e}") @@ -67,7 +68,7 @@ want_pad = config["Device"].get("Buttons", 0) want_finger = config["Features"].get("Touch") == "true" integrated_in = config["Device"].get("IntegratedIn", "").split(";") - is_touchscreen = set(integrated_in) & set(["Display", "System"]) + is_touchscreen = set(integrated_in) & {"Display", "System"} for match in config["Device"]["DeviceMatch"].split(";"): if not match or match == "generic": @@ -80,16 +81,16 @@ try: vid = int(vid, 16) pid = int(pid, 16) - except ValueError as e: + except ValueError: print(f"Invalid vid/pid in {match} in {f}", file=sys.stderr) - raise e + raise if bus == "usb": bus = 0x3 elif bus == "bluetooth": bus = 0x5 - class Tablet(object): + class Tablet: def __init__(self, name, bus, vid, pid, is_touchscreen=False): self.name = name self.bus = bus @@ -119,14 +120,14 @@ # Note: the actual name doesn't really matter, all our hwdb files use either "*" # or "* Finger", etc. It does matter for that "Finger" suffix though. query = f"libwacom:name:{tablet.name}:input:b{tablet.bus:04X}v{tablet.vid:04X}p{tablet.pid:04X}" - logging.debug(query) + logger.debug(query) r = subprocess.run( ["systemd-hwdb", "query", query], check=True, capture_output=True ) stdout = r.stdout.decode("utf-8").strip() assert stdout, f"No output recorded for query {query}" - logging.debug(stdout) + logger.debug(stdout) props = {} for line in filter(lambda line: len(line) > 1, stdout.split("\n")): print(line) @@ -149,6 +150,7 @@ assert "ID_INPUT_TOUCHPAD" in props # For the Wacom Bamboo Pad we check for "Pad Pad" in the device name - if "Pad" in tablet.name: - if "Wacom Bamboo Pad" not in tablet.name or "Pad Pad" in tablet.name: - assert "ID_INPUT_TABLET_PAD" in props + if "Pad" in tablet.name and ( + "Wacom Bamboo Pad" not in tablet.name or "Pad Pad" in tablet.name + ): + assert "ID_INPUT_TABLET_PAD" in props diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/tools/clean_svg.py new/libwacom-2.20.0/tools/clean_svg.py --- old/libwacom-2.19.1/tools/clean_svg.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/tools/clean_svg.py 2026-09-07 08:48:53.000000000 +0200 @@ -20,8 +20,8 @@ import logging import sys -from pathlib import Path from argparse import ArgumentParser +from pathlib import Path from xml.etree import ElementTree as ET logging.basicConfig(level=logging.INFO) @@ -84,8 +84,7 @@ def remove_non_svg_nodes_and_strip_namespace(root): - if root.tag.startswith(BRACKETS_NAMESPACE): - root.tag = root.tag[len(BRACKETS_NAMESPACE) :] + root.tag = root.tag.removeprefix(BRACKETS_NAMESPACE) for elem in list(root): if ( not elem.tag.startswith(BRACKETS_NAMESPACE) @@ -109,7 +108,7 @@ values = transform[len(TRANSLATE) + 1 : -1].split(",") try: x, y = float(values[0]), float(values[1]) - except Exception: + except Exception: # noqa: BLE001 return apply_translation(node, 1, 0, 0, 1, x, y) @@ -117,7 +116,7 @@ values = transform[len(MATRIX) + 1 : -1].split(",") try: a, b, c, d, e, f = [float(value.strip()) for value in values] - except Exception: + except Exception: # noqa: BLE001 return apply_translation(node, a, b, c, d, e, f) apply_scaling(node, a, d) @@ -137,8 +136,8 @@ new_y = x * b + y * d + 1 * f node.attrib[x_attr] = str(new_x) node.attrib[y_attr] = str(new_y) - except Exception: - pass + except Exception: # noqa:BLE001 + print(f"Failed to apply translation: {e}", file=sys.stderr) def apply_translation_to_path(node, x, y): @@ -183,8 +182,8 @@ h = float(node.attrib[h_attr]) node.attrib[w_attr] = str(w * x) node.attrib[h_attr] = str(h * y) - except Exception: - pass + except Exception as e: # noqa: BLE001 + print(f"Failed to apply scaling: {e}", file=sys.stderr) def to_string_rec(node, level=0): @@ -202,7 +201,7 @@ for attr in get_node_attrs_sorted(node): attr_value = node.attrib.get(attr) if attr_value is not None: - attribs.append(indent + ' %s="%s"' % (attr, attr_value)) + attribs.append(indent + f' {attr}="{attr_value}"') string = indent + "<" + tag_name + "".join(attribs) if len(node) or node.text: @@ -215,7 +214,7 @@ for child in get_node_children_sorted(node): string += to_string_rec(child, level + 1) string += indent - string += "</%s>" % tag_name + string += f"</{tag_name}>" else: string += " />" return string @@ -269,20 +268,20 @@ if child.tag == "rect" or child.tag == "circle": if button_assigned: continue - child.attrib["id"] = "Button%s" % _id - child.attrib["class"] = "%s Button" % _id + child.attrib["id"] = f"Button{_id}" + child.attrib["class"] = f"{_id} Button" button_assigned = True elif child.tag == "path": if path_assigned: continue - child.attrib["id"] = "Leader%s" % _id - child.attrib["class"] = "%s Leader" % _id + child.attrib["id"] = f"Leader{_id}" + child.attrib["class"] = f"{_id} Leader" path_assigned = True elif child.tag == "text": if label_assigned: continue - child.attrib["id"] = "Label%s" % _id - child.attrib["class"] = "%s Label" % _id + child.attrib["id"] = f"Label{_id}" + child.attrib["class"] = f"{_id} Label" child.text = _id label_assigned = True @@ -359,7 +358,7 @@ ET.register_namespace("", NAMESPACE) try: tree = ET.parse(svgfile) - except Exception as e: + except Exception as e: # noqa: BLE001 sys.stderr.write(str(e) + "\n") sys.exit(1) root = tree.getroot() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/tools/libwacom-update-db.py new/libwacom-2.20.0/tools/libwacom-update-db.py --- old/libwacom-2.19.1/tools/libwacom-update-db.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/tools/libwacom-update-db.py 2026-09-07 08:48:53.000000000 +0200 @@ -24,8 +24,8 @@ import argparse import configparser import os -import sys import subprocess +import sys import tempfile from pathlib import Path @@ -34,7 +34,7 @@ return Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config")) / "libwacom" -class Tablet(object): +class Tablet: def __init__(self, name, bus, vid, pid): self.name = name self.bus = bus @@ -46,7 +46,7 @@ # We have everything in strings so let's use that for sorting later # This will sort bluetooth before usb but meh - self.cmpstr = ":".join((bus, vid, pid, name)) + self.cmpstr = f"{bus}:{vid}:{pid}:{name}" def __lt__(self, other): return self.cmpstr < other.cmpstr @@ -137,9 +137,9 @@ # for tablets with re-used usbids and that doesn't matter try: bus, vid, pid, *_ = match.split("|") - except ValueError as e: + except ValueError: print(f"Failed to process match {match} in {file}", file=sys.stderr) - raise e + raise name = config["Device"]["Name"] t = Tablet(name, bus, vid, pid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/tools/list-local-devices.c new/libwacom-2.20.0/tools/list-local-devices.c --- old/libwacom-2.19.1/tools/list-local-devices.c 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/tools/list-local-devices.c 2026-09-07 08:48:53.000000000 +0200 @@ -344,6 +344,9 @@ dir = g_dir_open("/dev/input", 0, &error); if (!dir) { + /* Probably running in a container */ + if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT) + return EXIT_SUCCESS; fprintf(stderr, "%s\n", error->message); return EXIT_FAILURE; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libwacom-2.19.1/tools/show-stylus.py new/libwacom-2.20.0/tools/show-stylus.py --- old/libwacom-2.19.1/tools/show-stylus.py 2026-07-20 05:12:17.000000000 +0200 +++ new/libwacom-2.20.0/tools/show-stylus.py 2026-09-07 08:48:53.000000000 +0200 @@ -30,7 +30,7 @@ import libevdev import pyudev except ModuleNotFoundError as e: - print("Error: {}".format(str(e)), file=sys.stderr) + print(f"Error: {e!s}", file=sys.stderr) print( "One or more python modules are missing. Please install those " "modules and re-run this tool." @@ -92,9 +92,7 @@ if not d.absinfo[libevdev.EV_ABS.ABS_MISC]: die("Device only supports generic styli") - tool_bits = set( - c for c in libevdev.EV_KEY.codes if c.name.startswith("BTN_TOOL_") - ) + tool_bits = {c for c in libevdev.EV_KEY.codes if c.name.startswith("BTN_TOOL_")} styli = {} # dict of (type, serial) = proximity_state current_type, current_serial = 0, 0 in_prox = False @@ -132,7 +130,7 @@ except KeyboardInterrupt: print("Terminating") - return [s[0] for s in styli.keys()] + return [s[0] for s in styli] def load_data_files(): @@ -164,7 +162,7 @@ for stylus_id in config.sections(): ids = stylus_id.split(":") if len(ids) > 1: - _, sid = map(lambda x: int(x, 16), ids) + _, sid = (int(x, 16) for x in ids) else: _ = 0x56A # vid sid = int(ids[0], 16)
