Skip to content

Friday, 10 May 2024

Lambda表达式

匿名函数是很多高级语言都支持的概念,如lisp语言在1958年首先采用匿名函数。匿名函数有函数体,但没有函数名。C++11中引入了lambda表达式。利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读。但是从本质上来讲,lambda表达式只是一种语法糖,因为所有其能完成的工作都可以用其它稍微复杂的代码来实现。但是它简便的语法却给C++带来了深远的影响。如果从广义上说,lamdba表达式产生的是函数对象。

相同类似功能我们也可以使用函数对象或者函数指针实现:函数对象能维护状态,但语法开销大,而函数指针语法开销小,却没法保存范围内的状态。lambda表达式正是结合了两者的优点。

声明Lambda表达式

1
2
3
4
5
6
7
// 完整语法
[capture list] (params list) mutable(optional) constexpr(optional)(c++17) exception attribute -> return type { function body };

// 可选的简化语法
[capture list] (params list) -> return type {function body}; //1
[capture list] (params list) {function body};//2
[capture list] {function body};//3
  • capture list:捕获外部变量列表,不能省略;
  • params list:形参列表,可以省略(但是后面必须紧跟函数体);
  • mutable指示符: 可选,将lambda表达式标记为mutable后,函数体就可以修改传值方式捕获的变量;
  • constexpr:可选,C++17,可以指定lambda表达式是一个常量函数;
  • exception:异常设定, 可选,指定lambda表达式可以抛出的异常;
  • attribute:可选,指定lambda表达式的特性;
  • return type:返回类型
  • function body:函数体

标号1. 函数声明了一个const类型的表达式,此声明不可改变capture list中的捕获的值。

标号2. 函数省略了返回值,此时如果function body内含有return语句,则按return语句返回类型决定返回值类型,若无则返回值为void类型。

标号3. 函数无参数列表,意味无参函数。

1
2
3
vector<int> vec{1,0,9,5,3,3,7,8,2};

sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });

捕获外部变量

lambda表达式最前面的方括号的意义何在?其实这是lambda表达式一个很Hong要的功能,就是闭包。这里我们先讲一下lambda表达式的大致原理:每当你定义一个lambda表达式后,编译器会自动生成一个匿名类(这个类当然重载了()运算符),我们称为闭包类型(closure type)。那么在运行时,这个lambda表达式就会返回一个匿名的闭包实例,其实一个右值。所以,我们上面的lambda表达式的结果就是一个个闭包。闭包的一个强大之处是其可以通过传值或者引用的方式捕捉其封装作用域内的变量,前面的方括号就是用来定义捕捉模式以及变量,我们又将其称为lambda捕捉块。

Lambda表达式可以捕获外面变量,但需要我们提供一个谓词函数([capture list]在声明表达式最前)。类似参数传递方式:值传递、引入传递、指针传递。在Lambda表达式中,外部变量捕获方式也类似:值捕获、引用捕获、隐式捕获

值捕获

1
2
3
4
5
int a = 123;
auto f = [a] { cout << a << endl; };
f(); // 输出:123
a = 321;
f(); // 输出:123

值捕获和参数传递中的值传递类似,被捕获的值在Lambda表达式创建时通过值拷贝的方式传入,类中会相应添加对应类型的非静态数据成员。在运行时,会用复制的值初始化这些成员变量,从而生成闭包。因此Lambda表达式函数体中不能修改该外部变量的值; 因为函数调用运算符的重载方法是const属性的。同样,函数体外对于值的修改也不会改变被捕获的值。 想改动传值方式捕获的值,那么就要使用mutable

1
2
3
auto add_x = [x](int a) mutable { x *= 2; return a + x; };  // 复制捕捉x

cout << add_x(10) << endl; // 输出:30

因为一旦将lambda表达式标记为mutable,那么实现的函数调用运算符是非const属性的。

引用捕获

1
2
3
4
int a = 123;
auto f = [&a] { cout << a << endl; };
a = 321;
f(); // 输出:321

引用捕获的变量使用的实际上就是该引用所绑定的对象,因此引用对象的改变会改变函数体内对该对象的引用的值。 对于引用捕获方式,无论是否标记mutable,都可以在lambda表达式中修改捕获的值。

隐式捕获

隐式捕获有两种方式,分别是 [=]:以值补获的方式捕获外部所有变量 [&]:表示以引用捕获的方式捕获外部所有变量

1
2
3
int a = 123, b=321;
auto df = [=] { cout << a << b << endl; }; // 值捕获
auto rf = [&] { cout << a << b << endl; }; // 引用捕获

其他

捕获外部变量形式
[ ]不捕获任何变量(无参函数)
[变量1,&变量2, …]值(引用)形式捕获指定的多个外部变量
[this]值捕获this指针
[=, &x]变量x以引用形式捕获,其余变量以传值形式捕获
[*this]通过传值方式捕获当前对象
[&, x]默认以引用捕获所有变量,但是x是例外,通过值捕获

既然只使用一次,那直接写全代码不就行了,为啥要函数呢?——因为lambda可以捕获局部变量

在上面的捕获方式中,注意最好不要使用[=][&]默认捕获所有变量。首先说默认引用捕获所有变量,你有很大可能会出现悬挂引用(Dangling references),因为引用捕获不会延长引用的变量的声明周期:

1
2
3
4
std::function<int(int)> add_x(int x)
{
return [&](int a) {return x+a;};
}

因为参数x仅是一个临时变量,函数调用后就被销毁,但是返回的lambda表达式却引用了该变量,但调用这个表达式时,引用的是一个垃圾值,所以会产生没有意义的结果。如果通过传值的方式来解决上面的问题:

1
2
3
4
std::function<int(int)> add_x(int x)
{
return [=](int a) { return x + a; };
}

使用默认传值方式可以便面悬挂引用问题.但是采用默认值捕获所有变量仍然有风险。例如当在类中捕获私有变量,当返回值为lambda表达式时,无法捕获到私有变量,但当指定为[=]时,会捕获到this指针的副本,当类已经调用析构函数,使用该指针仍然不安全.

参数

  • 参数列表中不能有默认参数
  • 不支持可变参数
  • 所有参数必须要参数名(相当于不可以有占位参数)

返回类型

单一的return语句可以推断返回类型;多语句则默认返回void,否则报错,应指定返回类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 正确,单一return语句
transform(vi.begin(),vi.end(),vi.begin(),
[] (int i) {
return i<0? -i; i;
}
);
// 错误。不能推断返回类型
transform(vi.begin(),vi.end(),vi.begin(),
[] (int i) {
if (I<0) return -i;
else return i;
}
);
// 正确,尾置返回类型
transform(vi.begin(),vi.end(),vi.begin(),
[] (int i) ->int{
if (I<0)
return -i;
else
return i;
}
);

赋值

auto和function可接受lambda表达式的返回:

1
2
3
int x =8,y=9;
auto add = [](int a,int b){return a+b;};
std::function<int(int,int)> Add = [=] (int a,int b){return a+b};

lambda表达式产生的类不含有默认构造函数、赋值运算符、默认析构函数。至于闭包类中是否有对应成员,C++标准中给出的答案是:不清楚的,看来与具体实现有关。还有一点要注意:lambda表达式是不能被赋值的:

1
2
3
4
5
auto a = [] { cout << "A" << endl; };
auto b = [] { cout << "B" << endl; };

a = b; // 非法,lambda无法赋值
auto c = a; // 合法,生成一个副本

因为禁用了赋值操作符:

1
ClosureType& operator=(const ClosureType&) = delete;

但是没有禁用复制构造函数,所以可以用一个lambda表达式去初始化另外一个lambda表达式而产生副本。并且lambda表达式也可以赋值给相对应的函数指针,这也使得你完全可以把lambda表达式看成对应函数类型的指针

新特性

C++14中,lambda又得到了增强,一个是泛型lambda表达式,一个是lambda可以捕捉表达式。

lambda捕捉表达式

lambda表达式可以按复制或者引用捕获在其作用域范围内的变量。而有时候,我们希望捕捉不在其作用域范围内的变量,而且最重要的是我们希望捕捉右值。所以C++14中引入了表达式捕捉,其允许用任何类型的表达式初始化捕捉的变量:

1
2
3
4
5
6
7
8
// 利用表达式捕获,可以更灵活地处理作用域内的变量
int x = 4;
auto y = [&r = x, x = x + 1] { r += 2; return x * x; }();
// 此时 x 更新为6,y 为25

// 直接用字面值初始化变量
auto z = [str = "string"]{ return str; }();
// 此时z是const char* 类型,存储字符串 string

可以看到捕捉表达式扩大了lambda表达式的捕捉能力,有时候你可以用std::move初始化变量。这对不能复制只能移动的对象很重要,比如std::unique_ptr,因为其不支持复制操作,你无法以值方式捕捉到它。但是利用lambda捕捉表达式,可以通过移动来捕捉它:

1
2
3
4
auto myPi = std::make_unique<double>(3.1415);

auto circle_area = [pi = std::move(myPi)](double r) { return *pi * r * r; };
cout << circle_area(1.0) << endl; // 3.1415

原文章

Thursday, 9 May 2024

Kirigami Addons 1.2 is out with some accessibility fixes and one new component: FloatingToolBar.

Accessibility

During the accessibility sprint, there was an effort to ensure the date and time pickers were actually accessible. Aside from improving the screen reader support, this also allow to write Selenium integration tests which uses these components in Itinerary. Thanks Volker, David Redundo and others for working on this!

FloatingToolBar

Mathis and I worked on a new addition to Kirigami Addons adding to the existing FloatingButton and DoubleFloatingButton components. This component is perfect to add tool to editing and drawing areas and can either contain a simple RowLayout/ColumnLayout containing ToolButtons or a Kirigami.ActionToolBar.

import org.kde.kirigamiaddons.components
import org.kde.kirigami as Kirigami

FloatingToolBar {
 contentItem: Kirigami.ActionToolBar {
 actions: [
 Kirigami.Action {
 ...
 }
 ]
 }
}

 

Dialogs

With the style used by FormCardDialog and MessageDialog merged in Kirigami and soon in qqc2-desktop-style too, I did some changes to the FormCardDialog and MessageDialog to use the same padding as Kirigami.Dialog.

MessageDialog now works better on mobile with the layout adapting itself to the dialog size.

messagedialog with a mobile layout
messagedialog with a mobile layout

Aditionally similar to KMessageBox, MessageDialog has an optional “don’t show again” option which can be enabled by setting the dontShowAgainName property similar to the KMessageBox api.

I also prepared these two components to work as standalone windows which is likely to come with this Qt 6.8 change request.

Dialog in Qt 6.8
Dialog in Qt 6.8

CategorizedSettings

Jonah fixed a bug where it would be impossible to escape the settings on mobile.

Documentation

I added more screenshot to the API documentation and updated the TableView example app to use a ‘frameless’ style.

 

Qt 6.7 support

This release also brings support for Qt 6.7 on Android as this release introduced an API and ABI change to the Android code. Thanks Joshua for tackling this issue.

The new Ubuntu LTS was released in April, congratulations to all involved with that. I know Scarlett worked hard to get Kubuntu back into shape so do if that a try if you want a stable Plasma 5 desktop.

In the KDE neon project we don’t like to sit still for long so we are now building all our KDE packages on Ubuntu Noble, versioned 24.04. This always takes longer than it feels like it should, mostly because it’s a moving target to keep everything compiled as more KDE software gets released, so no promises on when it’ll be ready but we’ll try to be fast because the old Ubuntu base of jammy (22.04) is showing its age with projects like Krita no longer able to compile there.

So far the main issues are all the changes needed for 64-bit time_t to fix the y2k38 problem, we know you wouldn’t want your clocks to zero out in 2038.

KDE has a symbiotic relationship with many linux distros, since while we develop our software we also use particular versions of linux, I personally use archlinux as my distro of choice for many years being the only distro that I manage to bare for more than six months ( and I believe I am using it for more than 15 years already so that counts).

The "recipe" for packaging KDE software for arch is big, because we are big, and packaging large amounts of software is no easy feat, so me and Antonio Rojas started to update the build scripts to be less manual and less error prone. All the versions of Plasma 6 that have been packaged for arch are using this scripts in one way or another (or manually when we broke everything :)

This work is being done in a separate branch to not break the current workflow, but things are looking good and we hope to merge this in master soon, so that deploying newer versions of KDE software for arch will be a single command, meaning more time for the developers and less time creating packages.

Wednesday, 8 May 2024

KGraphViewer 2.5.0 has been just released! The main focus of this release is the port to Qt6 and KDE Frameworks 6 as well as general code modernisation, but of course some bugs have been squashed too. The full changelog can be found below.

About KGraphViewer:

KGraphViewer is a Graphviz DOT graph file viewer, aimed to replace the other outdated Graphviz tools. Graphs are commonly used in scientific domains and particularly in computer science.

You can learn more at https://apps.kde.org/kgraphviewer/

URL: https://download.kde.org/stable/kgraphviewer/2.5.0/
SHA256: 872bee63fb4df6f7fb2b4eaf02ff825cba3ca953ac02509a287fe5cd0f1e2b69
Signed by: D81C 0CB3 8EB7 25EF 6691 C385 BB46 3350 D6EF 31EF Heiko Becker heiko.becker@kde.org
https://invent.kde.org/sysadmin/release-keyring/-/raw/master/keys/heikobecker@key1.asc

Full changelog:

  • appstream: Add upcoming 2.5.0 release
  • Brush up menu & action terms a bit
  • Add icons to more actions & submenus
  • Update homepage URL in README
  • Remove some outdated/unused files
  • Avoid double look-ups in maps, use iterator returned from find method
  • Add widget parent to QMenu instances
  • DotGraphView: create popup menu only on demand
  • Share also zoom actions between DotGraphView & KGraphViewerPart
  • Use enum QColor constructor instead of string based one
  • Use KStandardAction convenience creation methods, parent all to collecitions
  • Drop file_open_recent from ui.rc files, given KStandardAction toolbar magic
  • Use more member-function-pointer-based Qt signal/slot connects
  • Port away from auto-casting from ascii strings
  • Fix missing closing tags in D-Bus API xml files
  • Use QList directly instead of Qt6-times alias QVector
  • Make manual build & install fully optional
  • Update links to graphviz website
  • Fix handling file cmdl arguments with relative path
  • Fix bad defaults for fonts, also for colors, shapes & style
  • KGraphViewerPart CMake config file: drop KGraphViewerPart_INCLUDE_DIRS
  • Bump version & SO version for first Qt6-based release
  • Drop support for Qt5/KF5
  • Clean up includes & forward declares
  • Do not use Qt modules includes
  • Deploy custom pixmaps as Qt resource
  • Printing page settings: remove custom broken window icon
  • Printing page settings: replace "lock ratio" button with checkbox
  • KGraphViewer KPart metadata: use normal app display name as name
  • Drop libkgraphviewer appstream file, no other libraries provide some
  • Set target properties right after declaring the target
  • Remove unused version header includes
  • Drop code for no longer supported KF versions
  • Fix another wrong min Qt version variable name usage
  • Use ECMDeprecationSettings
  • Port away from deprecated QMouseEvent::globalPos()
  • KGraphEditor: fix bad port to QMessageBox::question
  • Use Q_EMIT instead of emit
  • Switch to ECM required-default KDE_COMPILERSETTINGS_LEVEL
  • Remove unneeded ; after Q_DECLARE_PRIVATE() & Q_DECLARE_PUBLIC()
  • Use more nullptr
  • Fix wrong min Qt version variable name usage
  • Add Qt6/KF6 build support
  • Remove unneeded QApp::setOrganizationDomain, dupl. KAboutData::setApp...Data
  • appdate: use desktop-application type, add developer & launchable tags
  • Update homepage to apps.kde.org
  • Port away from deprecated QDesktopWidget
  • Port away from deprecated QPrinter::setOrientation()
  • Port away from deprecated QPrinter::numCopies()
  • Port away from deprecated operator+(Qt::Modifier, Qt::Key)
  • Port away from deprecated QWheelEvent::delta()/orientation()
  • Port away from deprecated signal QButtonGroup::buttonClicked(int)
  • Port away from deprecated I18N_NOOP2
  • Port away from deprecated KXmlGui RESTORE() macro
  • Bump min required Qt/KF to 5.15.2/5.100.0
  • Port away from deprecated QLayout::setMargin()
  • Add missing includes for Qt6 build
  • Remove unused include
  • Drop usage of outdated no-effect QGraphicsView::DontClipPainter
  • Port away from deprecated QStyle::PM_DefaultLayoutSpacing
  • change QFontMetrics.width with horizontalAdvance
  • replace QRegExp by QRegularExpression
  • Use for instead of foreach
  • Replace deprecated endl with Qt variant
  • remove -qt5 suffix
  • change path in gitlab-ci
  • snapcraft: initial import snapcraft files.
  • kgrapheditor: deploy ui.rc file as Qt resource
  • Remove Designer's "." normaloff file data from icon properties in .ui files
  • Add explicit moc includes to sources for moc-covered headers
  • doc: use a non-deprecated entity for Frameworks
  • Add releases
  • Add Open Age Content Rating
  • Remove warning about unknown DOT fonts
  • Remove custom action to configure shortcuts
  • Init graph members
  • Remove unused graphviz/gvc.h includes
  • Add KI18n and KDocTools macro to install translations
  • Port away from deprecated KMessageBox Yes/No API
  • Remove arcconfig
  • Add interface library for part include dir
  • Handle Qt6 change around enterEvent
  • Add missing include
  • Remove unused include
  • Port away from deprecated KPluginLoader
  • Port away from deprecated endl
  • Adapt build system to Qt6
  • Remove pointless/broken icons
  • Enable highdpi pixmaps
  • Add git blame ignore file
  • Add GitLab CI
  • Use ecm_qt_install_logging_categories to generate kdebugsettings file
  • Drop code variants for no longer supported Qt/KF versions
  • Use more target-centric cmake code
  • Update .gitignore
  • Use non-deprecated KDEInstallDirs variables
  • Port away from deprecated KSelectAction::triggered(QString)
  • Documentation updates - Update date and fix version numbers - Fix tagging and sync option's text
  • Port away from deprecated QMatrix
  • KAboutData::setupCommandLine() already adds help & version options
  • kgraphviewer_part.desktop: remove unused key Categories
  • Use .in suffix for header file that is passed to configure_file()
  • Port away from deprecated signal QProcess::error
  • Use default window flags for QInputDialog::getText
  • Port away from deprecated KEditToolBar::newToolbarConfig
  • Port to new KPluginMetaData-based KParts API
  • Deploy ui.rc files as Qt resources
  • Remove broken argument SERVICE_TYPES kpart.desktop from desktop2json call
  • Handle Graphviz capitalization changes
  • Capitalize Graphviz consistently
  • cmake: Simplify and improve FindGraphviz.cmake
  • Add KDE ClangFormat on CMake and run the target
  • Fix link: ui.html -> menus.html
  • Draw empty arrowheads closed
  • add genericname for use on kde.org/applications
  • Set StartupWMClass in desktop file
  • Use more https in links (and update outdated ones)

Massif Visualizer 0.8.0 has been just released! The main focus of this release is the port to Qt6 and KDE Frameworks 6 as well as general code modernisation, but of course some bugs have been squashed too. The full changelog can be found below.

About Massif Visualizer:

Massif Visualizer is a tool that - who'd guess that - visualizes massif data. You run your application in Valgrind with --tool=massif and then open the generated file in the visualizer. Gzip or Bzip2 compressed massif files can also be opened transparently.

You can learn more at https://apps.kde.org/massif-visualizer/

URL: https://download.kde.org/stable/massif-visualizer/0.8.0/src/
SHA256: 5fad3f0e0d9fbb6bc8cfb744cb4e2c99f231d57ee0dd66dd594d36c2cc588a80
Signed by: D81C 0CB3 8EB7 25EF 6691 C385 BB46 3350 D6EF 31EF Heiko Becker heiko.becker@kde.org
https://invent.kde.org/sysadmin/release-keyring/-/raw/master/keys/heikobecker@key1.asc

Full changelog:

  • appdata: Add upcoming 0.8.0 release
  • Unbreak KDE CI config: require "@stable-kf6" branch of kgraphviewer
  • KDE CI: require tests to pass (for platforms where they currently do)
  • KDE CI config: require "@same" branch of kgraphviewer
  • appstream: use new id without hyphen
  • Port away from QScopedPointer
  • ParseWorker: fix switched error title & text for empty data file
  • Overhaul action & title texts to follow KDE HIG, add more UI marker contexts
  • Config dialog: align "Shorten Templates" checkbox with form fields
  • Config dialog: avoid full-width comboboxes, use system style
  • Update outdated Kate editor setting replace-trailing-space-save
  • Use more function-pointer-based Qt signal/slot connections
  • Remove some unused includes
  • Use KStandardAction (member-)function-pointer-based overloads
  • Use ECM-requirement-derived default KDE_COMPILERSETTINGS_LEVEL
  • Drop any margins around document & tool views
  • Use QList directly instead of Qt6-times alias QVector
  • Switch from target_link_libraries' legacy LINK_PRIVATE to PRIVATE
  • Use more target-centric cmake code
  • CMake: remove unneeded explicit addition of current dirs to include dirs
  • Fix build with older cmake: -D not expected with COMPILE_DEFINITIONS
  • Update homepage to apps.kde.org
  • Use commits.kde.org/kgraphviewer as source location for KGraphViewerPart
  • Set version to 0.8.0
  • Use CMake's project(VERSION)
  • Drop support for Qt5/KF5
  • Support Qt6/KF6 builds
  • Rely on CMake's autorcc (enabled by KDECMakeSettings) to add Qt resources
  • Use ECMDeprecationSettings
  • Use KF6-proof KConfigGroup::group() overload
  • Port away from deprecated KPluginFactory::create() overload
  • Port away from deprecated KPluginLoader::factory()
  • Port away from deprecated KFilterDev
  • Port away from deprecated QPrinter::pageRect()
  • Port away from deprecated QDesktopWidget
  • Port away from deprecated QString::split overload
  • Port away from deprecated QPixmap::grabWidget
  • Port away from deprecated QTreeView::sortByColumn overload
  • Port away from ModelTest copy to QAbstractItemModelTester
  • Adapt iterator type to match actual type returned from QHash method
  • Add explicit QRegExp includes
  • Port away from deprecated QAlgorithmsPrivate::qReverse
  • Port away from deprecated qSort
  • Bump min required CMake/Qt/ECM/KF to 3.16/5.15.2/5.100/5.100
  • appstream: use https for screenshot links
  • appstream: use desktop-application type, add developer & launchable tags
  • Appdata: Add developer name
  • [CI/CD] Add flatpak job
  • [CI] Don't depend on kgraphviewer on Windows
  • Port to new CI template syntax
  • snapcraft: initial import snapcraft files.
  • Deploy ui.rc files as Qt resource
  • Move Flatpak CI to GitLab
  • Add explicit moc includes to sources for moc-covered headers
  • Use non-deprecated KDEInstallDirs variables
  • Install translations
  • Port away from deprecated KMessageBox::sorry
  • Remove arcconfig
  • Remove unused include
  • Use imported target for KGraphViewerPart
  • debug
  • Add Gitlab CI
  • Remove unused XmlPatterns
  • Add some missing linkages
  • Use KDE_INSTALL_MIMEDIR instead of custom XDG_MIME_INSTALL_DIR
  • appdata.xml: Minor fixes for submission to Flathub
  • Fix minor issues found by EBN
  • fix xml
  • update screenshot
  • Set StartupWMClass in desktop file
  • ui.rc files: use <gui> instead of deprecated <kpartgui>
  • Do not duplicate work done by KAboutData::setupCommandLine()
  • Use nullptr
  • Use override
  • Fix window icon for non-desktopfile WM to own icon "massif-visualizer"
  • Properly support BUILD_TESTING
  • Remove explicit enable_testing(), duplicated from KDECMakeSettings
  • Bump min cmake version to 3.0
  • Remove explicit use of ECM_KDE_MODULE_DIR, is part of ECM_MODULE_PATH
  • Fix minor EBN issues

Tuesday, 7 May 2024

Here's our bi-monthly update from KDE's personal information management applications team. This report covers progress made in the months of March and April 2024.

Since the last report, 36 people contributed more than 1300 code changes. Most of the changes will be available in the coming KDE Gear 24.05 release.

Akonadi

When Akonadi stores the timestamp of when a database entry has been last modified, the conversion from user's local time zone to UTC and back now works correctly regardless of the database engine used BKO#483060.

KOrganizer

KOrganizer has received a number of bug fixes:

  • Fixed parsing of events with all-day recurrence rules (BKO#483707)
  • KOrganizer now correctly tracks active (selected) tasks in the ToDo View (BKO#485185)
  • Creating a new event from the date navigator in top left corner uses the correct date now (BKO#483823)
  • Custom filters for event views in KOrganizer work again (BKO#484040)
  • Improved handling of calendar colors
  • The iCal Resource now correclty handles iCal calendars generated by Google Calendar, which previously caused an endless loop and high CPU usage by the Akonadi iCal Resource (BKO#384309)
  • The ToDo view in the KOrganizer side-bar now works even when the Todo View isn't open
  • The "Custom Pages" settings page, which didn't worked for years, have been removed
  • Fixed a crash on exit after the Settings dialog was opened (BKO#483336)

g10 Code has kindly sponsored Dan's work on those bug fixes and improvements.

Kontact

  • Fixed name of UI element being too long (Hide/Show Sidebar) (BKO#484599)

KMail

  • Fixed a regression in the message composer that caused attachments to not get automatically encrypted when encrypting a message (T7059)
  • Fixed not translated shortcut (BKO#484281)
  • Fixed Monochromatic icons in system tray not always used (BKO#484420)
  • Fixed some not extracted i18n string (BKO#484186)
  • Allow to change print layout when we export as pdf (BKO#480733)
  • Fixed KMail unexpectedly trying to connect to safebrowsing.googleapis.com (BKO#483283)
  • Fixed KMail's config dialog taking a long time to show up (BKO#484328)

Identity Management

A new feature will arrive in 24.08: Plasma-Activities support (only Linux). So these class were adapted for supporting it. A check was added in KMail/Akregator/Knotes/KAddressbook, all work is in progress at the moment.

Kleopatra

The certificate details (user IDs, subkeys, certifications, etc.) are now shown in a single window. Additionally, information about the smart cards a certificate is stored on is now shown.

Further improvements are:

  • The creation of OpenPGP certificates was simplified by replacing the complicated advanced settings with a simple selection of the algorithm and the validity period.
  • If the search for certificates on a server takes longer, a progress dialog shows that the search is still ongoing. If no certificates are found, a corresponding message is shown instead of just showing an empty list of results. (T6493)
  • Certificates stored on TCOS smart cards (e.g. the German Signature Card V2.0) are now imported automatically. Previously, the import had to be triggered manually. (T6846)

KNotes

Akregator

Martín González Gómez implemented a new article theme for Akregator which is not only more readable for long-form content but also adapts correctly to dark color themes.

Akregator's new dark article theme.

Akregator has received a number of bug fixes:

Itinerary

Our travel assistance app Itinerary now shows more details about vehicle and train coach amenities, informs about daylight saving time changes at travel destinations and received many more fixes and improvements for extracting travel documents. See Itinerary's own bi-monthly status update for more details.

Itinerary showing train ammentities in journey search results.

Merkuro

Merkuro now make uses of the new Date and Time picker from Kirigami Addons instead of bringing it's own. The date picker instance is also now shared in multiple places to reduce memory and CPU usage and speedup opening the even editor.

Merkuro date picker

Various dialogs were also modernized.

Merkuro import dialog

Get Involved

Join us in the #kontact:kde.org Matrix channel or the kde-pim mailing list!

Monday, 6 May 2024

About QML Efficiency: Compilers, Language Server, and Type Annotations

In our last post we had a look at how to set up QML Modules and how we can benefit from the QML Linter. Today we’re going to set up the QML Language Server to get an IDE-like experience in an editor of our choice. We’ll also help the the QML Compiler generate more efficient code.

Continue reading About QML Efficiency: Compilers, Language Server, and Type Annotations at basysKom GmbH.

Hello and sorry about the late post. I’ve been busy moving and other stuff that’s gotten in the way. I will also be idling the beginning of this month, so the next update may be shorter too.

Anyway, let’s get into the changes!

Kensa

I originally wanted to bring some of the “power-user” features from KSysGuard into the new System Monitor. I was rightfully turned down because they were hesitant of there being any use for most people and to prevent feature creep.

They suggested creating a seperate application instead. So Kensa, the detailed process viewer is born! It’s still mostly copy & pasted from old KSysGuard/libksysguard code, but updated for Qt6/KF6. And to make it clear, It’s very clearly modeled after the Window’s Process Explorer.

I have the general tab for viewing some basic information about the process. Said tab also includes an “Open With” so you can quickly open the executable in a hex viewer like Okteta.

The general tab

The memory maps tab shows what the process has mapped, mostly notably which shared libraries it’s currently using.

The memory maps tab

The open files tab makes it’s return as well, extremely useful.

The open files tab

And one of my own design, an environment variables tab. In the future I want to add a “Strings” tab for quickly viewing the executable strings and the ones currently in memory.

The environment tab

Note that Kensa is very early in development and not user-friendly. You currently have it give it a PID manually and lacks a process list.

Tokodon

[Feature] The window title now corresponds to the current page. This makes it easier to identify from a task bar, too. We know the title is duplicated inside the application as well (on desktop), but that’s Kirigami’s design decision. [24.05]

[Feature] If your server doesn’t provide a human-readable error message, the network error is displayed instead. This is useful to see if the DNS lookup failed or some other network-related reason the server is inaccessible. [24.05]

[Feature] Support for QtMultimedia has been added in situations where your system lacks or cannot use libmpv. This is preparatory work for a Windows version. [24.05]

[Feature] In the same vein as the patch above, QtWebView is now optional and I included even more authentication fixes. Previously I enforced an in-app web view to facilitate authentication (compared to the external web browser method or auth code in previous versions.) This was only a stop-gap solution until I had more time to flesh out our authentication system, but now I feel much happier about it’s current state. [24.05]

System Monitor

[Bugfix] Fix the column configuration dialog being shown too small on the Overview page. [6.0.4]

[Feature] Add the About KDE page to the hamburger menu. [6.1]

[Bugfix] Made sure cell tooltips shows up more reliably. [6.1]

[Feature] Added a menu item to copy the current column’s text. This makes System Monitor just as usable as the old KSysGuard for me now, because I tend to copy the command line a lot. (And PIDs.) [6.1]

Ruqola

[Bugfix] Use a better fitting icon for attaching files. The previous icon - when viewed at 16px - turned into something completely different. [2.1.2]

PlasmaTube

[Feature] Added support for viewing a channel’s playlists. [24.05]

[Feature] I also added a Craft blueprint for Android. Note that this is only preliminary and the Android version is nowhere near ready yet. I guess this could be used for a future Windows version too.

[Feature] I implemented more functionality in the PeerTube backend, so now it’s possible to log in and perform searching. Subscriptions work too, but I’m running into an issue where yt-dlp fails to pull certain videos. If you know anything about using yt-dlp with PeerTube, please let me know if there’s a workaround. [24.05]

[Feature] Added a new feature to import/export OPML subscriptions. This only works for YouTube channels at the moment, PeerTube support TBA. [24.05]

Gwenview

[Feature] I changed the old save bar to use the standard KMessageWidget widget. This isn’t just for looks, it fixes a lot of odd visual bugs and removes a ton of cruft in the process. [24.08]

The new Gwenview save bar. If it doesn’t look “out of place”, then my patch did it’s job!

NeoChat

[Bugfix] Fixed the share dialog not appearing properly, and improve the keyboard navigation inside of it. [24.05]

Frameworks

[Bugfix] Remove some redundant QML_ELEMENT declarations which in turn reduces runtime warnings. [6.1.0]

[Bugfix] Two KMessageWidget improvements, by fixing handling of color palette changes and making the icon label vertically centered. This is for that Gwenview patch. [6.1.0]

Android

I once again sat down and fixed a ton of build and runtime issues for our Android applications, and started fixing some of the Qt 6.7 fallout. NeoChat and Tokodon build and run again, and spent some time ironing out their issues.


That’s all this month!

Sunday, 5 May 2024

Down the rabbit hole

A few months ago I was kind of toying with the idea to start contributing to Plasma Mobile because I was getting increasingly fed up with Android and I realized if Linux Mobile was going to be my daily driver before I need to buy a new phone I better help out.

Then, after a few trivial commits I've seen that for the Plasma 6 release the navigation gestures were (at least temporarily) turned off - and since I am a very big fan of navigation gestures because they are objectively the best way to interact with a phone I just couldn't have that and I went about fixing them.

A bit of context

Why did the gestures even break by the upgrade to Plasma 6? Well, in Plasma Mobile 5 the navigation gestures were implemented in quite a hacky way - an invisible panel at the bottom screen edge that captured finger touches and handled the gesture and visual effect. While this worked this required a bunch of data moving around from KWin to the shell to show the window thumbnails which is unnecessary overhead.

So for Plasma 6 Devin Lin rewrote the entire task switcher, including the navigation gestures, to be a KWin effect which should make it perform better and use more of its infrastructure to need less bespoke code.

This went mostly quite smoothly, with few hiccups along the way. Unfortunately one of those hiccups was gestures (which now moved to KWin's EffectTogglableTouchBorder interface) simply not working anymore.

Fixing gestures

The fix was surprisingly simple: In the constructor for setting up the task switcher, including all shortcuts and gestures for it, the reconfigure function was simply never called which in turn meant the KWin::EffectTogglableTouchBorder::setBorders function was never executed. As you might imagine "setting the border" is quite a crucial part of having working gestures and one function call later gestures worked again!

Or did they

Disclaimer: I'm shuffling around the timeline a bit to make this post easier to follow, this part actually didn't happen until quite late.

Turns out the gestures did work - but oddly enough only after opening the Action Drawer at least once after every screen geometry change (eg: screen rotation). But the Action Drawer doesn't have anything to do with the task switcher and its gestures, how did it have an effect on them?

Well the reason is-... Honestly, I have no freaking clue. It makes no sense, but I also didn't really investigate it all that much, because I stumbled on the cause by accident quite quickly.

It turns out that the KWin people have done a good job at making the setBorders function quite safe to use and before reserving a touch border for an effect they first un-reserve anything that used to be on that border beforehand so two effects don't have to argue about who is allowed to react to the gesture. The problem is that for some reason in the reconfigure function in the task switcher effect logic also unreserved and reserved the borders, kind of doing setBorders job already before calling it.

Now why exactly that interfered with reserving the border I don't know, in theory setBorders should unreserve our previous stupidity and set us up properly - but evidently it didn't and when I removed our unnecessary border shenanigans in reconfigure suddenly gestures magically started working again. Either way, it's fixed now.

But define "working"

Well, it turns out that while KWin's border gesture infrastructure is quite nice, it also... doesn't allow customizing the distance a user needs to move their finger for a gesture to be "completed". It also turns out that on the PinePhone (and probably quite a few other phones) this lead to the gesture being... pretty much impossible to use. You just had to move your finger waaaaaayyyy too far (on the PinePhone about 3/4 of the screen height, see MR linked in next paragraph for video examples) to invoke the gesture. That's just unacceptable!

Luckily the fix is quite easy and a quick MR to KWin allowed us to set custom gesture distances-... or so I thought.

I mean, it did allow us to set the gesture distance, but that didn't mean the gestures were much better, so I went for another approach.

The rabbit hole.

(I'm talking about this monster of an MR from here on out, it also contains a video example of the almost-final product)

Ooooooh boy.

I'll have you know that I have quite strong feelings towards what navigation gestures need to be able to do to be a nice user experience.

One very crucial part of this for me is being able to "flick away" an app and go to the homescreen. The old navigation gestures didn't support that - to go to the homescreen you needed to open the switcher, then tap on the side to close it. That's TWO WHOLE FINGER TAPS - UNACCEPTABLE (Well, one drag and one tap, but let's not be pedantic).

And while we're at it, having "quick task switch" gestures would also be really nice - but I'll keep those for followup MRs, first I need to just revamp the task switcher backend to support tracking gesture velocity to discern between a drag with a pause at the end or a quick flick.

Velocity Tracking

I'm gonna gloss over a lot of the details, but for a quick too-long-didn't-care-enough-to-write-it-all-down: KWin's gesture system doesn't expose gesture positions, just percentage based activation factors so I had to do some work to massage that into giving me the right data.

After said massaging we now magically get the "primary" and "orthogonal" gesture position from KWin we can sit down to create velocity tracking

Moving average

My first gut reaction was to implement a normal moving average calculation and after chatting a bit with Devin it seems other projects went for a similar approach. But then I looked at the moving average calculation in other places and... it looked so complicated and bloated and over the top to store all the past values and iterate through the entire list of them to average them out and doing all that every frame and ...

As someone who initially learned programming by working with microcontrollers this was unacceptable (I see, this word is becoming a recurring theme). Now let's step back a bit and figure out what we actually need. The moving average is just there to filter out spikes in movement speed, be it due to inaccurate sensor touch screen readings, frametime spikes or accidentally slipping with the finger. We only want to filter, we do not actually care about receiving a mathematically accurate moving average. In fact we couldn't care less about getting a mathematically accurate moving average for our velocity.

We only want to filter

Damn. Now if only someone knew how to choose and design filters.

Looks at Uni curriculum

Oh would you look at that! Signal theory, control technology and filter design this semester. I can finally procrastinate AND study for a course at the same time!

Exponentially Weighted Moving Average

Even though I have a course on filter design at Uni, I never said I was any good at it. I mean, I'm okay enough, but not good enough to explain this filter better than Wikipedia does. The upshot of it is: It is a filter that does not need to store the entire history it tries to filter (no ugly array of values to iterate through: check), it is essentially a low pass filter (filters out transient spikes in movement speed: check) and it can be implemented in essentially 30 lines of code in a single function without any loops (not overcomplicated and bloated: check).

In fact, the EWMA filter is just a single formula that takes the previous filtered velocity, the current speed in the last time step (~frame) and a magic smoothing factor and spits out the filtered velocity updated with the newest sensor values. So that's just two lines for the actual filter (1 per axis) and some boilerplate. Neat!

Magic smoothing factor

Usually you'd pick a smoothing factor based on the sampling rate of your system and your desired time constant. To emulate the behavior of moving averages I found elsewhere I picked a time constant of 30ms. This (very roughly) means, when starting from 0, a sudden input value is applied to the filter, it will reach ~63% of the input after 30ms - and after another 30ms it will have reached ~90%. This is roughly in line with an "proper" moving average with a window of 60-70ms.

The problem we now have is that we don't have a fixed sampling interval - we get new gesture positions whenever KWin deems fit to give us some (which might be seconds apart if the user doesn't move the finger for a while). Sooooo what now? If we get a very long timescale our "roughly equivalent to a 60ms moving average" goes right out of the window.

Well, luckily with one simple formula we can calculate our smoothing factor based on a desired time constant and a certain sampling interval which we can call every time we get a new value:

smoothing_factor = 1 - exp(-delta_time/desired_time_constant)

(Maybe someday I'll add a LaTeX parser to the blog. Or I just copy in a screenshot. We'll see)

Now there is one remaining problem: As a self-respecting microcontroller dev who absolutely knows he is not restricted by a 16MHz CPU without a floating point arithmetic unit, but still cannot shake old habits that having e to the power of a floating point number in that formula hurts.

Luckily there is an approximation formula that is a bit cheaper

smoothing_factor = delta_time/desired_time_constant

That approximation formula should only be used when the delta time is a lot smaller than the desired time constant, which we

checks notes

Oh. We don't really satisfy that condition. Eh. Whatever. We only need it to filter out super high weird spikes and be roughly in the right ballpark, we don't need to propulsively land a rocket.

Some manual checks later show we'll not be all that far off the "correct" formula and we need to put a clamp on it anyways to always do a bit of smoothing so we'd deviate from the right formula anyways.

Do our "recalculate smoothing factor on every new value" shenanigans interfere with the stability or correctness of our filter? Probably, I dunno. But it's probably fine and throughout all of my testing, both throwing in arbitrary test values and empirical testing while using the gestures it all felt nice, so I give it my seal of approval!

Now... where were we? Right!

Flick!

And now with a simple check on if speed > threshold we can detect flicks! And voila - an upwards flick goes to homescreen!

2D gestures

Well, I know I said I'll replicate the old gesture behavior without touching any functionality and keep any extra features for followup MRs, but the gesture feels kinda bad when it only goes up and down and doesn't follow the finger left and right as well - and thanks to our previous excursion into KWin it also magically exposes the orthogonal gesture position, so we can just really quickly hook that up and have X and Y tracking.

States?!?!?!

As a remnant from Devin's move to a KWin effect there was a bit of a mess of what keeps state where - he simply didn't have enough time to refactor the entire thing while also updating the rest of the shell to KF6 and all the fun API breakages and so there were several places that kept track of the same-ish state that made things confusing and hard to work with.

No problem, I can refactor that and take some work off of Devin.

Quick task switch gesture

But you know what, now the task switcher code feels really clean and nice and it would be so easy to just add a few lines of logic to discern between an upwards flick and a diagonal flick to switch to neighboring tasks.

Ah to hell with it, let's add that as well!

Task Scrub

Remember how I said I have opinions on what good gestures are?

Well, I really really really dislike what Android does with their task switcher where it uses some heuristic to only reorder the tasks based on recency after you have been in a task for a while. This allows you to use the quick task switch gesture several times in a row to go "further back" in the task history.

But it's also kind of a black box as to when that happens and it really annoys me a lot - besides, the quick task switch gesture is neat for one switch, but gets very tiring to use when you have to use it several times in a row.

So how about a bespoke "task scrub" gesture that activates on a mostly-horizontal gesture invocation and allows to scrub through a large number of recent tasks.

Right.

I've skipped over a lot of detail and some entire sidequests in this story (with a lot of potential for more jokes) for the sake of brevi-WOW HOW IS IT OVER 2000 WORDS ALREADY?!

Uhm.

Wrapping Up

There's still some bugs to fix, some tasks for later MRs (though much fewer than I thought there would be) and some decisions to make, but for now this has been my small odyssey about first fixing then slightly extending then completely rewriting the task switcher and navigation gestures for Plasma Mobil