Skip to content

Monday, 2 January 2023

Happy new year! To get a good start in this new new year, I’m happy to announce that Tokodon 23.01.0 is out! This is a new major release for Tokodon and while it’s been only 2 weeks since the last major release, this release is packed with new features and improvements.

Tokodon is a Mastodon/Pleroma/Nextcloud Social client built with Kirigami that I started back in spring 2021. Tokodon has a great integration with KDE Plasma and Plasma Mobile, but it also work on other desktop environments and even Windows and macOS.

Get it!

You can download Tokodon 23.01.0 from Flathub and from the F-Droid using the KDE repo. Currently we don’t offer binaries for Windows and macOS but if you want to help with that, please get in touch. build

New timeline design

The first thing you will notice, when trying out this new version, is the new layout of the timelines.

I updated it to follow more closely the design of Mastodon web-UI and I also spent some time adjusting the spacing and typographie to be more consistent.

Tokodon main view
Tokodon main view

It is now possible to search for posts, accounts and tags directly from within Tokodon.

Search field inside tokodon
Search field inside tokodon

Hashtag Handling

Tokodon now handles hashtags better. Previously, when clicking on a hashtag, Tokodon would redirect you to the website where you could see the posts that included the selected hashtag. Now you don’t need to leave Tokodon anymore, and the posts are displayed inside the app like any other timeline.

Conversation View

Tokodon now includes a basic conversation view. This shows the list of your last direct conversations. This makes it possible to see your conversation in a much nicer way than with the latest mentions view.

Conversation in Tokodon
Conversation in Tokodon

I plan to improve this feature further in the future, as I will be adding support for conversation markers and maybe offer a real chat-like view for conversations (which I will shamelessly steal from NeoChat).

Poll Support

It’s now possible to view and interact with polls. This supports both multiple choice and single choice polls, but creating new polls is still not possible.

Poll in Tokodon
Poll in Tokodon

Account Editor

I also added an account editor. The merge request was actually 10 months old and I started it during a stream at the last FOSDEM. As you might imagine, it was not that fun to rebase. But it is finally possible to edit your account metadata and preferences directly from Tokodon.

Account editor
Account editor

I also submitted a pull request in Mastodon itself to expose more settings in the API.

Real-Time Timeline Update

Tokodon was already handling some real-time events coming from the server, but until now this only included notifications. Now Tokodon will also handle new incoming messages and add them to the timeline. It will also delete messages as soon as the server asks for them to be deleted.

Technical Details

Aside from the many new features, there was several large re-factorings of the code base to cleanup some code that younger-me wrote. The C++ code base now has a coverage of 35%, and I am pretty happy with this increase from 12% of the previous release.

Coming next, I want to focus more on the post editor. The back-end also needs to be cleaned up and several important features are still missing (choosing the language, posting polls and adding alternative textual descriptions to images). I already created a branch for that and you can follow the work on this merge request.

And for those who prefer a full changelog, here it is:
  • Update year
  • Update to 23.01
  • Cleanup notification model
  • Cleanup loading handling
  • Fix timezone handling
  • Remove dead code
  • Remove refreshing button now that refreshing happens automatically
  • implemented update notifications
  • Tweak appstream summary
  • timelinemodel fix crash if json array is empty
  • Fix unit tests
  • Fix loading timelines
  • Correctly handle streaming event about new and deleted posts
  • Remove debug output
  • Release new version 22.12.0
  • Cleanup and fix account model
  • Fix search on mobile
  • Reduce number of warning in logs
  • TootComposer.qml fix qmlscene issue "missing ":""
  • Run clang format
  • Fix rendering of poll when no vote has been submitted
  • Handle pressing back button with image preview open
  • Remove dead code
  • AuthorizationPage.qml authorize token URL should wrap
  • Add more tests
  • Cleanup backend code for profile edition
  • Port to mobileform
  • Account editor (second try)
  • fix: No Preview for Hashtag links
  • Dont't show account switcher when no account is loaded
  • Fix clazy issues
  • Fix some compile warning
  • More testing
  • Add tests for threading
  • Improve thread UI
  • Fix opening thread
  • Clang format
  • Add more tests and fix canFetchMore behavior
  • Fix marking post as pinned
  • More refactoring
  • Remove fetching and fully replace by loading
  • Tag handling
  • Ship our own icon
  • Update icon name
  • Fix checkable state
  • Add unit test
  • Use breeze icons
  • Add conversation view
  • Remove dead code
  • Handle case where no spelled is installed
  • Fix crash in notification view when interacting with post
  • Propagate visibility in replies
  • Don't reset timeline when switching account
  • Fix accountModel returned by follow activity
  • Display blurhash when loading image
  • Don't show link preview on mobile
  • Fix replies count
  • Improve default debug output
  • Optimize tooltip in PostDelegate
  • Fix fetching the global timeline
  • Fix replying to someone add yourself as mention
  • Improve spacing of text field
  • Improve overall spacing
  • Add more unit tests
  • Implement searching for accounts and posts
  • Add a NetworkProxy page to settings
  • Port AuthorizationPage to MobileForm
  • Improve layout of already voted polls
  • Add more tests
  • Implement polls in the frontend
  • Add poll implementation in backend
  • Fix test
  • Reduce spacing between action and author
  • Update post layout
  • Remove duplicate headers between cpp/h files
  • Workaround kirigami regression
  • Don't show drawer handle when showing full screen image
  • Fix crash when loading own account
  • Fix appdata version

Get Involved

If you are interested in helping, don’t hesitate to reach out in the Tokodon matrix channel (#tokodon:kde.org) and I would be happy to guide you.

I’m also regularly posting about my progress on Tokodon (and other KDE apps) on my Mastodon account, so don’t hesitate to follow me ;)

And in case, you missed it, as a member of the fundraising working group, I need to remind you that KDE is currently running an end of the year campaign. Don’t hesitate to donate!

Packager section

You can find the package on download.kde.org and it has been signed with my GPG key.

Kraft, which was released as version 1.0 after long time of active development, is targetted to the Linux desktop. My firm conviction is that the Linux desktop is very suitable for the target group of Kraft: In the small office of craftsmen for example, a Linux desktop is a great work horse which is stable, very well adoptable and has a great amount of applications that are stable and maintained.

These are only the most obvious points why Kraft is so far only available for Linux.

But often enough switching to Linux is another hurdle that users have to go, coming from a more mainstream world. So it is great to learn that Kraft, as many UI applications, can be run unter the Windows Subsystem for Linux (WSL) on Windows systems quite flawlessly.

Kraft running on Windows Desktop It was tried with Windows 11 Home and the Kraft AppImage of 1.0.

The steps to run Kraft in WSL:

  • Make WSL running on the Windows installation
  • Install a X-server on the Windows machine
  • Create a Debian or Ubuntu Linux subsystem
  • Install a few extra packages into the Linux installation
  • Download and run the Kraft AppImage 1.0

A more detailed howto and discussion can be found in the easy cash & tax forum. Thanks Thomas for bringing up the topic and providing the Howto!

Sunday, 1 January 2023

Dear digiKam fans and users,

A new year means new goals, and this one is a challenge: migrating the old digiKam documentation based on DocBook format to a new architecture, more simple and easy to maintain. After 20 years, we left the DocBook manual for the modern Sphinx/ReStructuredText framework. This one is really a pleasure to use by documentation writers.

The content is published in a dedicated web site, internationalized by the KDE translation teams. An EPUB version is also available for the off-line use cases.

Friday, 30 December 2022

Two month ago, in October 2022, KDE's GitLab made me use a two-factor authentication (2FA). Without a second factor, I was no longer able to push code, comment on merge requests, or contribute anything meaningful on KDE Invent.

For a long time, I have known I should use two-factor authentication for my important accounts; especially for those accounts used to commit code other people are executing because they trust me. But I was too lazy to have everything prepared to use the second factor.

Thanks to Ben and the KDE infrastructure team, there were no more excuses and I had to set up a secure login.

Secure login, but don't lock yourself out 

Having a second factor, it is important that I am not locked out, if my second factor is left at home or broken. Here is what I did:

  1. The first step is to choose the second factor. I decided against dedicated hardware like a Yubi key. I am familiar with one-time passwords on my mobile phone, thus, I decided to use Time-based one-time password (TOTP). This means a device or mobile app knows a secret to calculate a six-digit one-time password. The password is only valid for a couple of seconds, then a new one can be generated locally. I use Google Authenticator, but there are alternatives from less controversial vendors. Just scan the QR code and verify the secret by once entering a one-time code.
  2. I installed Keepass to store the recovery codes in case my TOTP device is broken or stolen. As a side effect, I can now use more complex passwords for less frequently used passwords.
  3. I made a backup including the Keepass database.
  4. As a side-effect, I need to use tokens for checkouts and pushes. A great opportunity to have this aspect of secure development activated, too.

Remaining open questions

Some questions remain open for me. Time will tell, how much they bug me and where I need to adjust.

Currently, I only have my personal phone as a TOTP device. Maybe I want to add more phones or my iPad. I am also unsure whether I should install and use a TOTP software on my desktop like KDE Keysmith. It is a weighting of comfort, security, and reliability.

I have not yet made up my mind, how to handel the tokens for checkout and pushes. Having them in an open document in Kate might be more harmful then using my password as in the past. I consider storing them in Keepass, too.

By-product: More security everywhere

Now that I have everything prepared on my side to use TOTP as my two-factor authentication, it was easy to use it for all the other accounts that deserve some extra protection: GitLab.com, GitHub, and independent GitLab instances hosted by FOSS projects similar to KDE Invent. Even my Google account is now protected by a TOTP mechanism and I no longer get text messages to my mobile phone. Further, I stored ten security codes from Google, just in case.

Having a security spree, I also wanted to use TOTP for my banking accounts. Unfortunately, my banks insist on the use of their own app. I think they could benefit from using open and established standards, but they decided to force us costumers to install and use their apps.

Let’s go for my web review for the week 2022-52. Last one before 2023 appears.


2022 was the year of Linux on the Desktop - Justin Garrison

Tags: tech, linux, desktop, foss

There it is… at least for the developers and gamers demographic.

https://www.justingarrison.com/blog/year-of-linux-desktop/


I’m Done With Google

Tags: tech, DRM, vendor-lockin

More DRM anyone? It’s just a pain and locking people out.

https://deijin.bearblog.dev/im-done-with-google/


Here’s who helped Elon Musk buy Twitter - The Washington Post

Tags: tech, business, social-media, politics

As they say: follow the money. That gives an idea about the incentives and various agendas behind this take over.

https://www.washingtonpost.com/technology/2022/12/24/elon-musk-twitter-funders/


Escaping the Algorithms | Commonweal Magazine

Tags: tech, ai, gpt, culture, philosophy

There are a few reasons to worry about the latest strain of generative neural networks. One of them is the trust we can place in new generated content. The other one is indeed the impact on our culture. There’s been already a trend at focusing on what sells rather than what’s truly novel or avant-garde. This could well push it further. We’ll we drown in mediocre content?

https://www.commonwealmagazine.org/artificial-intelligence-AI-social-media-Heidegger


AI: Markets for Lemons, and the Great Logging Off

Tags: tech, ai, neural-networks, gpt, trust, culture

A few compelling arguments for the impact of the latest strain of generative neural networks. The consequences for the eroded trust about online content are clear. I’m less convinced about some of the longer term predictions this piece proposes though.

https://www.fortressofdoors.com/ai-markets-for-lemons-and-the-great-logging-off/


IDN is crazy | daniel.haxx.se

Tags: tech, security, dns

International Domain Names indeed opened a whole can of worms. This creates plenty of opportunities for confusions and mistakes waiting to happen… or to be exploited.

https://daniel.haxx.se/blog/2022/12/14/idn-is-crazy/


Dioxus

User interfaces that run anywhere Tags: tech, rust, frontend, webassembly

Looks like an interesting frontend stack. Still young but probably worth keeping an eye on.

https://dioxuslabs.com/


More use of Rust is inevitable in open source software

Tags: tech, system, programming, safety, rust

Like it or not, this is definitely filling a very unique niche. It’s a very good fit for system software where safety is important and available time limited. There is no better option for now.

https://utcc.utoronto.ca/~cks/space/blog/programming/RustIsInevitable


The Bitter Truth: Python 3.11, Cython, C++ Performance | Agents and Robots

Tags: tech, simulation, python, c++, performance

Python is getting faster but is still far from what you can get with C++ of course. That said, for simulations you likely don’t want everything in Python or in C++. Part of the challenge is to split the subsystems properly and use C++ where it matters.

https://medium.com/agents-and-robots/the-bitter-truth-python-3-11-vs-cython-vs-c-performance-for-simulations-babc85cdfef5


Hash Collision Probabilities

Tags: tech, hash, probability

Nice article. Keep an eye on potential collisions indeed. Depending on the use of your hashes this can be critical.

https://preshing.com/20110504/hash-collision-probabilities/


Golang is evil on shitty networks

Tags: tech, go, networking

This is indeed a strange default used for sockets there… will have bad consequences for sure in more situations than expected.

https://withinboredom.info/blog/2022/12/29/golang-is-evil-on-shitty-networks/


A Gentler, Better Way to Change Minds - The Atlantic

Tags: culture, life, values

Good and reasonable advices… doesn’t make them easy to truly apply though. It’s likely worth trying to live by them still.

https://www.theatlantic.com/family/archive/2022/04/arguing-with-someone-different-values/629495/


Tags: culture, public-domain

Now, rejoice! This is a big body of work entering public domain, at last! Will Mickey Mouse finally be next?

https://www.theverge.com/2022/12/28/23528003/sherlock-holmes-metropolis-to-the-lighthouse-public-domain-day-2023



Bye for now!

Thursday, 29 December 2022

What is a vacation without a nice side project? – My small x-mas project was to get my RISC-V Allwinner D1 Nezha board finally into a state that it shows anything on the connected HDMI-port. Any, “yeah!!!”, it works:

This picture shows qmlscene rendering a rotating yellow rectangle at 2 fps (speed is limited due to yet missing HW acceleration support).

A few words about the board

Compared to other embedded boards that I have, this one is surprisingly well documented; given you find the right webpages (list at the end). The vendor page itself is in a rather typical state, where an online translator occasionally comes handy to translate Chinese into something I understand 😉 But then, there is the really nice sunxi community wiki with has all extra information that you need.

For the device itself, some months ago I decided to get this one mostly because of the reasons price and delivery date. However, it has a big disadvantage for me when I use it for testing the KDE Yocto layers: There is only a 2D GPU on the board (namely a “G2D” unit) for which also no Kernel drivers are present at the moment (except those from the Kernel source blob by the device vendor). However, for all other parts there is impressive community work. Most notably, coming with Kernel 6.2, there is finally the HDMI driver support that made the above picture possible.

The few steps left for me

As said, there is a really good documentation about compiling a close-to-mainline Kernel and u-boot for this board. Moreover, the meta-riscv Yocto layer provides recipes to build a full device image with Kernel 5.16 and a patched/hacked u-boot (using an older boot sequence) with a nice out-of-the-box experience.

So, to get graphics/HDMI working on the board, all that was left for me was following the wiki documentation and:

  • switch to the latest Kernel fork based on 6.1 with all the relevant patches
  • and adapt U-Boot to a more recent fork that can boot this more mainline Kernel fork.

The details are summarized in this PR for the meta-riscv layer. It essentially drops as much non-mainline tweaks as possible and adapts the recipes along the way. Simple as it looks, it was quite a fun ride down the rabbit hole until I got my first booting Kernel 🙂 I really think that this tinkering around with hardware is the best way to learn its concepts. Even though I attended many talks in the past about the steps I did, it is so different when you are doing it yourself.

What comes next

Unfortunately, I do not expect any Plasma or KDE application running on the Nezha board in the sooonish future (at least not accelerated via the G2D chip)… Yet, if you recall, at FOSDEM 2019 Alistair already demonstrated Plasma running on a HiFive Unleashed board, using an expansion board for graphics. Finally, there is right now another very interesting and not too expensive RISC-V board becoming available with on-board 3D GPU and it is already on my shopping list… I am looking forward to 2023 🙂

Collected Links

Tuesday, 27 December 2022

Kraft 1.0 It is a pleasure to announce that Kraft Version 1.0 was released last week.

What is Kraft?

Kraft is free software to create office documents like offers and invoices in an efficient way. It runs on the Linux desktop and suits small businesses of all kinds.

After countless releases with version numbers 0.x, Kraft finally goes with version number 1.0 with this release. It is in production at several companies since many years, and with this release it got many more improvements that make it a really mature product.

Highlights

Lets take a look on the highlights of of version 1.0.

AppImage Support

Installing software properly is still a challenge for many users. AppImage comes to the rescue there: Single file, easy to download and start with all dependencies included makes it easy for users. For the creator, it is just one-fits-all, which makes it easy to maintain.

The new Kraft AppImage was carefully reworked and has now really all dependencies included, has a complete own icon set and was tested thoroughly. It is ready for production now.

Giro Code

Kraft now can print the EPC QR Code on invoices easily. Users just have to configure the bank account data to use, and Kraft creates the QR code automatically to be included in the documentation template.

User Manual

The Kraft user manual got great improvements again. It comes with even more and improved text, with much more screenshots and improved translations.

This is a community contributions that is so important for Kraft.

Many other Improvements

There were many other improvements: New functionality such as the new day counter for the number cycle templates (allows to have a counter in the document number that resets to 1 every day) or new modes for the watermark functionality to complete the generated PDF documents plus much more details (See Changelog).

How it continues

Kraft is up and running - and maintained. The plan is to keep the 1.0 as a kind of LTS in a stable branch, that only gets urgent fixes for stability.

For master, I am planning to do a couple of more intrusive changes that will take a bit longer.

See the roadmap discussion here.

Curious?

I hope you got a bit curious now about Kraft. Feel free to check it out using the AppImage.

If you find it an useful addition to the Linux application ecosystem that enables more users for Linux we’d very much appreciate your contribution!

Some more progress has been made on fixing my newest drawing tablet!

Fixing up the patch

So as described in the original post, I have to patch the uclogic HID driver. Let’s start by going through the process of submitting a patch upstream!

Before we even think about sending this patch upstream, I have to first - fix it. While the patch is mostly fine in it’s original form, there is one big issue I would like to tackle - which is the tablet frame buttons. Not even the original author seemed to figure out this issue, so I’m excited to jump in and figure it out.

First I want to set an end goal, which is to be able to set the tablet buttons through the new KDE Plasma 5.26 interface, like so:

Screenshot of the tablet settings page, screenshot by Nicolas Fella.

Currently if you run my new uclogic patch, for some reason it is not considered a “Pad”:

Screenshot of my tablet settings page, showing that no pads show up1.

Looking through the merge request shows.. nothing of interest. That’s because I actually needed to look at this KWin merge request which actually talks to libinput! Oh yeah, libinput - our old friend is here again. This MR mentions an event called LIBINPUT_EVENT_TABLET_PAD_BUTTON which is handled by evdev-tablet-pad.c in libinput. Huh, whats this?

...
static inline void
pad_button_set_down(struct pad_dispatch *pad,
		    uint32_t button,
		    bool is_down)
{
	struct button_state *state = &pad->button_state;

	if (is_down) {
		set_bit(state->bits, button);
		pad_set_status(pad, PAD_BUTTONS_PRESSED);
	} else {
		clear_bit(state->bits, button);
		pad_set_status(pad, PAD_BUTTONS_RELEASED);
	}
}
...

So this file seems to be handling “tablet pad” devices, which I didn’t even know were considered a separate device until now. Looking through the code reveals logic that libinput uses to decide what buttons reported by the device are meant for tablet pad usage:

...

static void
pad_init_buttons_from_kernel(struct pad_dispatch *pad,
			       struct evdev_device *device)
{
	unsigned int code;
	int map = 0;

	/* we match wacom_report_numbered_buttons() from the kernel */
	for (code = BTN_0; code < BTN_0 + 10; code++) {
		if (libevdev_has_event_code(device->evdev, EV_KEY, code))
			map_set_button_map(pad->button_map[code], map++);
	}

	for (code = BTN_BASE; code < BTN_BASE + 2; code++) {
		if (libevdev_has_event_code(device->evdev, EV_KEY, code))
			map_set_button_map(pad->button_map[code], map++);
	}

	for (code = BTN_A; code < BTN_A + 6; code++) {
		if (libevdev_has_event_code(device->evdev, EV_KEY, code))
			map_set_button_map(pad->button_map[code], map++);
	}

	for (code = BTN_LEFT; code < BTN_LEFT + 7; code++) {
		if (libevdev_has_event_code(device->evdev, EV_KEY, code))
			map_set_button_map(pad->button_map[code], map++);
	}

	pad->nbuttons = map;
}
...

So I created a list of valid pad inputs and used those to remap all of the pad buttons to valid inputs. This shouldn’t affect existing tablets (especially considering I don’t think anyone has used a tablet with this driver with more than a couple buttons).

...
/* Buttons considered valid tablet pad inputs. */
const unsigned int uclogic_extra_input_mapping[] = {
	BTN_0,
	BTN_1,
	BTN_2,
	BTN_3,
	BTN_4,
	BTN_5,
	BTN_6,
	BTN_7,
	BTN_8,
	BTN_RIGHT,
	BTN_MIDDLE,
	BTN_SIDE,
	BTN_EXTRA,
	BTN_FORWARD,
	BTN_BACK,
	BTN_B,
	BTN_A,
	BTN_BASE,
	BTN_BASE2,
	BTN_X
};
...
/*
* Remap input buttons to sensible ones that are not invalid.
* This only affects previous behavior for devices with more than ten or so buttons.
*/
const int key = (usage->hid & HID_USAGE) - 1;

if (key > 0 && key < ARRAY_SIZE(uclogic_extra_input_mapping)) {
        hid_map_usage(hi,
                        usage,
                        bit,
                        max,
                        EV_KEY,
                        uclogic_extra_input_mapping[key]);
        return 1;
}

And that’s pretty much the only major change I did to the original patch! You can see the patch in linux-input here.

However that isn’t the end of the story, as there’s one issue - libinput doesn’t think my tablet pad is a… tablet pad?

# libinput record /dev/input/event12
...
  udev:
    properties:
    - ID_INPUT=1
    - ID_INPUT_MOUSE=1
    - LIBINPUT_DEVICE_GROUP=3/28bd/91b:usb-0000:2f:00.3-4.1
...

Okay, that’s interesting - why is this a mouse? Uh oh, don’t tell me…

Fixing udev

So unfortunately before my tablet is fully functional, we have to touch another piece of critical Linux infrastructure - great. I want to dive into how libinput even decides device types, and I promise you it’s harder than it should be.

If you never touched the Linux input stack before (like I did before I started this project) you might think, “whats the big deal? the mouse says it’s a mouse, a keyboard says it’s a keyboard, whatever.” except it’s never that simple. If you’ve been reading my blog posts, you might think that’s just information evdev will hand over, which you’re wrong there too. All evdev tells userspace is what events the device will emit - that’s it2. So who figures out what is what?

Unfortunately, it’s a guessing game. No you heard me right, udev guesses what devices are. So how do we tell what devices are which? Luckily systemd ships with a hardware database, which details stuff like id vendors and manual fixes for esoteric devices. This is actually what the original patch author did in order to fix udev classifying it as a mouse:

id-input:*:input:b0003v28BDp091Be0100*
 ID_INPUT_MOUSE=0
 ID_INPUT_TABLET=1
 ID_INPUT_TABLET_PAD=1
...

However I didn’t like this solution, and it would be a pain to find the modalias for every single tablet that ever existed, that udev mistakenly categorizes. Is there a better solution? Instead I changed the logic in src/udev/udev-builtin-input_id.c. Let’s take a look at the original code path:

...
is_pointing_stick = test_bit(INPUT_PROP_POINTING_STICK, bitmask_props);
has_stylus = test_bit(BTN_STYLUS, bitmask_key);
has_pen = test_bit(BTN_TOOL_PEN, bitmask_key);
finger_but_no_pen = test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key);
for (int button = BTN_MOUSE; button < BTN_JOYSTICK && !has_mouse_button; button++)
        has_mouse_button = test_bit(button, bitmask_key);
has_rel_coordinates = test_bit(EV_REL, bitmask_ev) && test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel);
has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs);

/* unset has_mt_coordinates if devices claims to have all abs axis */
if (has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
        has_mt_coordinates = false;
is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props);
has_touch = test_bit(BTN_TOUCH, bitmask_key);
has_pad_buttons = test_bit(BTN_0, bitmask_key) && has_stylus && !has_pen;
...
if (has_mt_coordinates) {
        if (has_stylus || has_pen)
                is_tablet = true;
        else if (finger_but_no_pen && !is_direct)
                is_touchpad = true;
        else if (has_touch || is_direct)
                is_touchscreen = true;
}

if (is_tablet && has_pad_buttons)
        is_tablet_pad = true;

if (!is_tablet && !is_touchpad && !is_joystick &&
        has_mouse_button &&
        (has_rel_coordinates ||
        !has_abs_coordinates)) /* mouse buttons and no axis */
        is_mouse = true;

To explain a little of context, udev has several “built-in” commands to decide what devices are what, and if any quirks or workarounds need to be applied. Notably, the input_id builtin handles classifying input types for devices if they are not already in the hardware database. If you turn on udev debug logging, you can actually see the built-ins it runs whenever you connect, say a usb device to your system. As you can see, evdev gives udev the supported event types of the device, and then udev has to figure out what the device actually is. Now let’s look at the supported event types by the tablet pad:

# libinput record /dev/input/event12
...
devices:
- node: /dev/input/event12
  evdev:
    # Name: UGTABLET 21.5 inch PenDisplay Pad
    # ID: bus 0x3 vendor 0x28bd product 0x91b version 0x100
    # Supported Events:
    # Event type 0 (EV_SYN)
    # Event type 1 (EV_KEY)
    #   Event code 256 (BTN_0)
    #   Event code 257 (BTN_1)
    #   Event code 258 (BTN_2)
    #   Event code 259 (BTN_3)
    #   Event code 260 (BTN_4)
    #   Event code 261 (BTN_5)
    #   Event code 262 (BTN_6)
    #   Event code 263 (BTN_7)
    #   Event code 264 (BTN_8)
    #   Event code 265 (BTN_9)
    #   Event code 266 ((null))
    #   Event code 267 ((null))
    #   Event code 268 ((null))
    #   Event code 269 ((null))
    #   Event code 270 ((null))
    #   Event code 271 ((null))
    #   Event code 272 (BTN_LEFT)
    #   Event code 273 (BTN_RIGHT)
    #   Event code 274 (BTN_MIDDLE)
    #   Event code 275 (BTN_SIDE)
    # Event type 2 (EV_REL)
    #   Event code 6 (REL_HWHEEL)
    #   Event code 8 (REL_WHEEL)
    #   Event code 11 (REL_WHEEL_HI_RES)
    #   Event code 12 (REL_HWHEEL_HI_RES)
    # Event type 4 (EV_MSC)
    #   Event code 4 (MSC_SCAN)
...

I encourage you to read through the original systemd code, as the bug (I think) is hilariously obvious. The tablet pad never emits any BTN_STYLUS events. In fact, my tablet is not even configured on a firmware level to ever emit any BTN_STYLUS events, because the attached log above is without my patch! Obviously this is bad, as that means possibly other tablets are wrongly accused of being mice, and we should fix that logic. That’s also what I didn’t want to simply shove a new entry into the hardware database, as this turns out to be a udev bug.

So I made a systemd PR fixing the logic, maybe that might fix your tablet too!

Tilt support

One more thing I wanted to tackle was tilt support for the pen, which the driver says it supported but I haven’t tested yet. Simple, right? (you already know the answer to that question)

The first thing to do is just evdev:

# evtest /dev/input/event11
...
Event: time 1672152523.926503, -------------- SYN_REPORT ------------
Event: time 1672152523.938496, type 3 (EV_ABS), code 0 (ABS_X), value 37529
Event: time 1672152523.938496, type 3 (EV_ABS), code 1 (ABS_Y), value 13166
Event: time 1672152523.938496, type 3 (EV_ABS), code 27 (ABS_TILT_Y), value 12
Event: time 1672152523.938496, -------------- SYN_REPORT ------------
Event: time 1672152523.952501, type 3 (EV_ABS), code 27 (ABS_TILT_Y), value 13
Event: time 1672152523.952501, -------------- SYN_REPORT ------------
Event: time 1672152523.956501, type 3 (EV_ABS), code 0 (ABS_X), value 37534
Event: time 1672152523.956501, type 3 (EV_ABS), code 1 (ABS_Y), value 13138
Event: time 1672152523.956501, type 3 (EV_ABS), code 27 (ABS_TILT_Y), value 14
Event: time 1672152523.956501, -------------- SYN_REPORT ------------
Event: time 1672152523.962497, type 3 (EV_ABS), code 27 (ABS_TILT_Y), value 15
...

So it looks like it’s reporting tilt events, that’s good. Let’s go one layer up, and check with libinput. Actually, instead of using debug-events or record, libinput actually has a handy tablet testing function called debug-tablet:

#  libinput debug-tablet
Device: UGTABLET 21.5 inch PenDisplay Pen (event11)
Tool: pen serial 0, id 0
libinput:
tip: up
  x:                 299.38 [-------------------------------------------------|-----------------------------]
  y:                 140.64 [-----------------------------------------|-------------------------------------]
  tilt x:            -54.53 [---------------|---------------------------------------------------------------]
  tilt y:             41.21 [---------------------------------------------------------|---------------------]
  dist:                0.00 [|------------------------------------------------------------------------------]
  pressure:            0.00 [|------------------------------------------------------------------------------]
  rotation:            0.00 [|------------------------------------------------------------------------------]
  slider:              0.00 [---------------------------------------|---------------------------------------]
  buttons:
evdev:
  ABS_X:           29952.00 [-------------------------------------------------|-----------------------------]
  ABS_Y:           14077.00 [-----------------------------------------|-------------------------------------]
  ABS_Z:               0.00 [|------------------------------------------------------------------------------]
  ABS_TILT_X:        -55.00 [----|--------------------------------------------------------------------------]
  ABS_TILT_Y:         41.00 [-----------------------------------------------------------------|-------------]
  ABS_DISTANCE:        0.00 [|------------------------------------------------------------------------------]
  ABS_PRESSURE:        0.00 [|------------------------------------------------------------------------------]
  buttons: BTN_TOOL_PEN

Alright that’s good, it looks like libinput is recording the tilt too. How about inside of Krita, which has tilt support? Uhhh… let’s check the tablet tester:

Screenshot of the Krita tablet tester

Wait, there’s no way to check for tilt here! That was a really weird omission, so I fixed that in Krita 5.2. Then I thought there was no way that no developer in Krita somehow didn’t have tilt information debugged somewhere, so after a bit searching I found a tool for Tablet Event Logging activated by CTRL+SHIFT+T. Using that, we can find if Krita has picked up the tilt from our pen:

$ krita
...
krita.tabletlog: "[BLOCKED 2:] MouseMove        btn: 0 btns: 0 pos:  828, 515 gpos:  859,2778 hires:  858.956, 2777.95 Source:2"
krita.tabletlog: "[       ] TabletMove       btn: 0 btns: 0 pos:  828, 516 gpos:  859,2779 hires:  859.281,    2779 prs: 0.000000 Stylus Pen id: 0 xTilt: 0 yTilt: 0 rot: 0 z: 0 tp: 0 "
krita.tabletlog: "[BLOCKED 2:] MouseMove        btn: 0 btns: 0 pos:  828, 516 gpos:  859,2779 hires:  859.281,    2779 Source:2"
krita.tabletlog: "[       ] TabletMove       btn: 0 btns: 0 pos:  828, 517 gpos:  859,2780 hires:  859.441, 2779.72 prs: 0.000000 Stylus Pen id: 0 xTilt: 0 yTilt: 0 rot: 0 z: 0 tp: 0 "
krita.tabletlog: "[BLOCKED 2:] MouseMove        btn: 0 btns: 0 pos:  828, 517 gpos:  859,2780 hires:  859.441, 2779.72 Source:2"
krita.tabletlog: "[       ] TabletMove       btn: 0 btns: 0 pos:  829, 517 gpos:  860,2780 hires:  859.562, 2780.25 prs: 0.000000 Stylus Pen id: 0 xTilt: 0 yTilt: 0 rot: 0 z: 0 tp: 0 "
...

Huh? No tilt information at all? That’s slightly worrying. However, there is a layer in-between Krita and libinput, that being the compositor - in my case KWin. I actually didn’t know until now, but KWin has a handy debug tool available by searching KWin in KRunner:

Screenshot of the KWin Debugging Tool when searched in KRunner.

Using that, we can check for the input events that it records:

Screenshot of the KWin Debug Window

Well that’s a nice consolation, it looks like KWin is picking up the tilt information from libinput too, so at least it’s not throwing it out. But why does Krita still not receive anything? For some reason, Krita receives tilt information on X11.

To explain, Krita does not interface with KWin directly. Instead, it uses standard protocols - either X or Wayland to communicate with the server or compositor respectively. So why does tilt work when Krita is running under X11 and not when running under Wayland? The trick is that it doesn’t matter, currently Krita is always running under X since it disables Wayland support for some reason. However, XWayland is still technically a Wayland client, so naturally the next place to look is how KWin sends Wayland events. That takes us to the class KWaylandServer

The protocol we care about here is the unstable “tablet” Wayland protocol, currently on version 2. It supports tilt events, so what’s the problem here? In reality, KWin was never sending the events in the first place:

...
const quint32 MAX_VAL = 65535;
tool->sendPressure(MAX_VAL * event->pressure());
tool->sendFrame(event->timestamp());
return true;
...

I actually came across this function when searching through relevant KWin merge requests, notably !3231 which has the unrealistic goal of complete tablet support in just one merge request! I cleaned up the relevant tilt support part, and submitted a new merge request which means pen tilt/rotation is supported under KDE Wayland now! Yay!

Dials

All is well and good now, right? That’s what I thought, until I realized my dials don’t work! I was so entrenched in everything else, that I completely neglected these little do-dads. To explain, these seem to be XP-PEN specific and are just glorified scrollwheels:

Picture of a XP-PEN dial.

However, these are not Wacom rings. Rings on a Wacom tablet (to my knowledge) are actual rings, which report absolute positioning like a wheel. These dials are not those, but are sending relative “scroll” events. I had considered remapping this to buttons on the evdev layer, which was a bad idea since that meant that complicated things further up. Another option was to instead, emulate a Wacom ring by disguising the relative events and turning those into EV_ABS. I also threw that idea away, because that also seems to hide the problem.

If you’re curious, the dials actually worked without my patches - because remember that udev was classifying the pad as a mouse - so libinput thought no further. But now that it’s considered a real tablet pad, it rejects scroll wheel events.

Honestly the best way to solve this issue is to - unfortunately - touch every single bit of the input stack to accommodate these devices. Again.

  • The Wayland tablet protocol must be changed to add a few new properties for dials on pads. Tracking via !122.
  • Libinput must be modified to expose these dials and correctly map them. Tracking via !845.
  • KWin must be modified to support sending dial events in support of the tablet protocol changes. Currently not tracking.
  • These dials (and we should also include rings and strips too) should be exposed in the Tablet Settings KCM too. Currently not tracking either.

As you can see, it’s going to be a complex process to support these stupid little circles, but I’m going all in. Luckily, with the rest of my patches going through - everything except for dials on the XP-PEN Artist 22R Pro device should be well supported now. In the coming months, I hope to make headway in supporting dials in KDE.


  1. The settings page is bugged when you have no pads, in 5.27 the combo box will be disabled and say “None” like it should. ↩︎

  2. Technically, there is HID device types defined but as far as I can tell that’s only used internally in the kernel. ↩︎

Saturday, 24 December 2022

So I bought an art tablet this year, the XP-Pen Artist 22R Pro which comes with a pen. This pen does not work under Linux, sometimes.

My dirty, dusty 22R tablet.

While almost every part of the tablet works, only one of the two stylus buttons is functional. One button is middle mouse click, and the other one is right mouse click. For some reason, only the first stylus button works! This is obviously troublesome, so where do we begin to fix this issue? Let me take you on a journey, if you have no experience with how input works on Linux - well that makes two of us!

Figuring Out The Problem

I work in Krita, so the first place to check is Krita’s tablet testing tool first. Looking at the log yields us something like this:

The Krita Tablet Tester
...
Stylus move X=120.37 Y=129.63 B=4 P=0.0% S=0.0 (DRAW)
Stylus release X=120.37 Y=129.63 B=0 P=0.0% S=0.0
...

According to the legend, we only care about the section named B which tells us which button is pressed. On my pen it’s:

  • 0 is released (not pressing on the screen)
  • 1 is drawing (pressed on the screen, it doesn’t count hovering)
  • 4 is the “middle mouse” button
  • The nonfunctional button does not show up at all of course.

So that at least means Krita isn’t the root cause, also testing it on the desktop or any other application yields the same result - the button is non-functional. In some cases, I’ve found the button to actually turn off the stylus entirely, but I’m not sure why yet.

How does tablet input on Wayland actually function? Let’s move down a layer and look at KWin, the Wayland compositor for KDE Plasma.

On Wayland, input is typically handled using libinput, and now even recent X versions have a libinput driver. Digging through the libinput backend on KWin doesn’t reveal anything particularly exciting, so we’ll assume KWin isn’t at fault either for now. Luckily, libinput has a built-on logging utility we can use to check what it sees!

First we want to check what devices libinput sees:

# libinput list-devices
...
Device:           UGTABLET 21.5 inch PenDisplay Mouse
Kernel:           /dev/input/event11
Group:            5
Seat:             seat0, default
Capabilities:     pointer
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      disabled
Nat.scrolling:    disabled
Middle emulation: disabled
Calibration:      identity matrix
Scroll methods:   button
Click methods:    none
Disable-w-typing: n/a
Disable-w-trackpointing: n/a
Accel profiles:   flat *adaptive
Rotation:         n/a

Device:           UGTABLET 21.5 inch PenDisplay Keyboard
Kernel:           /dev/input/event12
Group:            5
Seat:             seat0, default
Capabilities:     keyboard
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      n/a
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Disable-w-trackpointing: n/a
Accel profiles:   n/a
Rotation:         n/a

Device:           UGTABLET 21.5 inch PenDisplay
Kernel:           /dev/input/event13
Group:            5
Seat:             seat0, default
Size:             477x268mm
Capabilities:     tablet
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      identity matrix
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Disable-w-trackpointing: n/a
Accel profiles:   none
Rotation:         n/a

So it looks like the device we’re interested in is/dev/input/event13. We can now view the debug event log:

# libinput debug-events --verbose
...
 event2   POINTER_MOTION          +25.044s       -1.66/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.045s       -1.66/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.046s       -1.87/  1.87 ( -1.00/ +1.00)
 event2   POINTER_MOTION          +25.047s       -1.87/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.049s       -1.38/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.050s       -1.38/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.051s       -1.66/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.053s       -1.38/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.055s       -1.11/  0.00 ( -1.00/ +0.00)
 event2   POINTER_MOTION          +25.057s       -1.11/  0.00 ( -1.00/ +0.00)
...

Oh right, there’s a lot of junk in there. We can slim it down to the only device we care about though:

# libinput debug-events --verbose --device /dev/input/event13
...
event13  TABLET_TOOL_AXIS        +9.455s               371.93*/88.01*  tilt: 8.06/15.12        pressure: 0.00
event13  TABLET_TOOL_AXIS        +9.545s               371.67*/88.07*  tilt: 8.06/15.12        pressure: 0.00
event13  TABLET_TOOL_BUTTON      +9.549s       331 (BTN_STYLUS) pressed, seat count: 1
event13  TABLET_TOOL_AXIS        +9.607s               371.38*/88.37*  tilt: 8.06/15.12        pressure: 0.00
event13  TABLET_TOOL_AXIS        +9.627s               371.38/88.56*   tilt: 8.19*/15.12       pressure: 0.00
...

As you can see, whenever I press the first stylus button it reports BTN_STYLUS, but when I press the second one it instead reports itself as BTN_TOUCH (not shown in the snippet).

Now before we go further, I just wanted to confirm whether or not the pen actually worked at all so I booted up Windows real quick to test. And it does work as expected, darn.

Going Deeper

Now it’s easy to assume libinput is the culprit and the one to be fixed, like I did. At first, I wrote up a quick patch to remap the wrong BTN_TOUCH inputs and inject proper BTN_STYLUS2 events but honestly that’s dirty. So what is beneath libinput? evdev!

So now that we know the (possible) culprit, we need to dig deeper into libinput. Like a good software project, libinput has developer documentation for us to look at.

Let’s check the event device that Linux gives us, using the handy evtest:

# evtest /dev/input/event13
...
Event: time 1671823416.485402, -------------- SYN_REPORT ------------
Event: time 1671823416.517402, type 4 (EV_MSC), code 4 (MSC_SCAN), value d0045
Event: time 1671823416.517402, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1671823416.517402, type 1 (EV_KEY), code 320 (BTN_TOOL_PEN), value 0
Event: time 1671823416.517402, type 3 (EV_ABS), code 26 (ABS_TILT_X), value 0
Event: time 1671823416.517402, -------------- SYN_REPORT ------------
...
Event: time 1671823416.825414, -------------- SYN_REPORT ------------
Event: time 1671823416.835640, type 4 (EV_MSC), code 4 (MSC_SCAN), value d0045
Event: time 1671823416.835640, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1671823416.835640, type 3 (EV_ABS), code 26 (ABS_TILT_X), value 29
Event: time 1671823416.835640, -------------- SYN_REPORT ------------

Uh oh, the same bug appears here too. So it’s time to sigh look deeper into the stack. Unfortunately, going deeper means stepping into the kernel. What is actually handling the input?

# lsusb -t
...
    |__ Port 4: Dev 5, If 0, Class=Hub, Driver=hub/2p, 480M
        |__ Port 1: Dev 8, If 0, Class=Hub, Driver=hub/4p, 480M
            |__ Port 3: Dev 9, If 0, Class=Human Interface Device, Driver=usbhid, 12M
            |__ Port 3: Dev 9, If 1, Class=Human Interface Device, Driver=usbhid, 12M
            |__ Port 3: Dev 9, If 2, Class=Human Interface Device, Driver=usbhid, 12M
...

It looks like the “usbhid” driver which makes sense, this is a USB HID device after all. However at this point is where I got stuck, because as far as I know there is no way to extract the specific HID driver in use (unless you know the actual module name). This is annoying, so I went digging inside of the kernel source tree for any mention of my device ID (0x091b). Nope. So in turn we can assume it’s using the generic HID driver, which is actually kind of impressive.

So what is the proper HID driver for this device? Well after some research it turns out to be uclogic which handles a bunch of UGTablet, Huion and other misc Asian tablet devices. Unfortunately, they haven’t added any support for this model but someone has.

Digimend Project

Luckily there is a project dedicated to upstreaming device drivers for these tablets, and Aren Villanuvea (also known as “kurikaesu”) known for userspace-tablet-driver-daemon has reverse engineered the tablet already. Better yet, he even implemented most of the work in uclogic already! You can see the PR here.

Now that’s where the story ends, yay - except that my device still doesn’t work. That’s because the PR never made it into Digimend, and it was closed by the author without explanation. And because it never made it into Digimend, it never landed upstream. It looks like Aren has decided it was a better use of his time to implement it into userspace instead.

The daemon is nice and all, but I would prefer kernel support for this device for numerous reasons. And what’s worse is that it’s so close to being complete that it sucks that the work hasn’t continued. Oh well…

Kernel Hacking

So now I’m trying to upstream the uclogic patch! Oh how I wish it was a bug in a higher layer… I’ll be taking over Aren’s work and trying to clean up the patch and reduce it down to just supporting the 22R Pro, since that’s the only tablet I own. Here’s what works:

  • Both stylus buttons work!
  • Pen pressure works.
  • Both dials work, although the right one is registered as horizontal scroll which is odd - that might have to be re-mappable on a higher layer.
  • The tablet buttons “work” but some of them are not registered properly as there’s more buttons than HID definitions for buttons. I might have to split this up into two devices, or something.

Now here’s my to-do list:

  • Hopefully receive Aren’s blessing to release the patches with his original ownership.
  • Figure out a fix with the tablet buttons, and contact Nicolas Fella (who is working on the re-mappable tablet buttons in 5.27) to see what needs to be done so they’re re-mappable in the new GUI.
  • Choose whether or not to contribute it directly to upstream (slow?) or back to Digimend.

If anyone is familiar with kernel contributions in the HID subsystem, or know the right people (like the ones mentioned in the article, hi!) I would love to get in contact!

Friday, 23 December 2022

Let’s go for my web review for the week 2022-51.


Charge - Blender Open Movie - Blender Video

Tags: tech, blender, 3d, movie

The latest Blender Open Movie. Again a very good one!

https://video.blender.org/w/04da454b-9893-4184-98f3-248d00625efe


UnifiedPush: a decentralized, open-source push notification protocol | F-Droid - Free and Open Source Android App Repository

Tags: tech, mobile, android, notifications

This is a big deal, it’s time we open up that can of worms.

https://f-droid.org/2022/12/18/unifiedpush.html


MSG defends using facial recognition to kick lawyer out of Rockettes show | Ars Technica

Tags: tech, surveillance

This is really creepy… how can this be even allowed?

https://arstechnica.com/tech-policy/2022/12/facial-recognition-flags-girl-scout-mom-as-security-risk-at-rockettes-show/


Okta’s source code stolen after GitHub repositories hacked

Tags: tech, security

This sounds like a bad series of events for such a company…

https://www.bleepingcomputer.com/news/security/oktas-source-code-stolen-after-github-repositories-hacked/


We are drowning in information while starving for wisdom | Realize Engineering

Tags: research, knowledge, ethics

This is indeed very much true… there’s a clear crisis in research. It turned into a hamster wheel of publishing articles at a constantly faster pace. The incentives are misguided which pushes that behavior to even have a career. Meanwhile, knowledge building suffers.

https://realizeengineering.blog/2021/01/20/we-are-drowning-in-information-while-starving-for-wisdom/


Photographer Fools the Internet With AI-Generated Cameras That Don’t Exist | PetaPixel

Tags: tech, ai, gpt, generator, fake

Don’t worry, so called AI isn’t going to take away your jobs. But do worry though, this marks the end of trusting any pictures or texts you see in the media. Everything needs to be challenged, even more so now.

https://petapixel.com/2022/12/15/photographer-fools-the-internet-with-ai-generated-cameras-that-dont-exist/


Cyberpunk Translate

Tags: tech, ai, neural-networks, translation

Interesting tool to for the automatic transcription and translation of videos using off the shelf components. Seems to work nicely.

https://github.com/elanmart/cbp-translate


Copilot Internals | Hacky repo to see what the Copilot extension sends to the server

Tags: tech, github, copilot, ai, machine-learning

Interesting reverse engineering job of Copilot’s client side to have a better idea at which information it actually feeds to the model. A couple of funny tricks to prepare the prompt are involved. Obviously some telemetry involved as well, again with interesting heuristics to try to figure out if the user kept the suggestion or not.

https://thakkarparth007.github.io/copilot-explorer/posts/copilot-internals.html


A not so unfortunate sharp edge in Pipenv :: dade

Tags: tech, python, supply-chain

This is indeed a problem in the way Pipenv handle this kind of cases. Makes for bisecting clearly troublesome.

https://0xda.de/blog/2022/12/a-not-so-unfortunate-sharp-edge-in-pipenv/


An Ode to Unit Tests: In Defense of the Testing Pyramid

Tags: tech, programming, tests, tdd, architecture, craftsmanship

Good piece. I like how it frames the debate, asking the right questions on where might be the assumptions on how testing is done.

https://www.infoq.com/articles/unit-tests-testing-pyramid/


The Cargo Cult of Good Code

Tags: tech, programming, craftsmanship

Good points, this shows quite effectively the problem with blindly following rules without keeping in mind the reasoning behind them.

https://pboyd.io/posts/cargo-cult-of-good-code/


Taming Names in Software Development - Simple Thread

Tags: tech, programming, craftsmanship

Excellent piece about naming things in code. The conclusion is perfect of course: it’s hard but it pays off.

https://www.simplethread.com/taming-names-in-software-development/


The Story of A - by Kent Beck

Tags: tech, architecture, refactoring, craftsmanship, xp

A good set of skills to develop to bring technical changes to a project. It doesn’t need to be overwhelming or a fight. If you doubt, if you have empathy and if you slice the proposals it can become doable and help the people around you.

https://tidyfirst.substack.com/p/the-story-of-a


The topologist’s world map – tafc.space

Tags: tech, map, art

This is really cool work. Very insightful and pretty to look at.

https://tafc.space/qna/the-topologists-world-map/



Bye for now! And Merry Christmas!