Skip to content

Thursday, 11 June 2026

Structure of code and logic for tournaments in the Mankala Engine.

So, we want the tournaments to be able to:

  • Create custom game rooms (with different variants, number of players, and time limit)
  • Join the rooms with room codes.
  • Create elimination brackets for players.
  • Have empty slots filled with computerized opponents.
  • A scoreboard after the game for final rankings.

The tournament is going to be part of the Multiplayer variant. For that, when a person clicks on Multiplayer game mode, they will be asked to select from the given two options of a casual 1 to 1 game or another a tournament. Then they will be asked to either create a room or join the room with the code.

Key elements to implement:

  • Room codes will be created by mapping XMPP MUC JIDs (e.g., A3F7K2 → tournament-a3f7k2@conference.server.com).
  • Fill computerized opponents: When it is detected that there is an absence of required players, the game will be filled with computer opponents in all the empty spots, just like we have for the vs AI game mode.

Here is an example of how the tournaments.cpp can be implemented:

class TournamentManager : public QObject {
    Q_OBJECT
    Q_PROPERTY(QVariantList tournaments READ getTournaments NOTIFY tournamentsChanged)
    Q_PROPERTY(QVariantMap activeTournament READ getActiveTournament NOTIFY activeTournamentChanged)
    
public:
    // --- Tournament duration ---
    Q_INVOKABLE QString createTournament(
        const QString& variant,       // "Bohnenspiel", "Oware", "Pallanguli"
        int maxPlayers,               // eg. 4, 8, 16
        int durationDays,             // tournament duration
        const QString& organizerJid   // creator's XMPP JID
    );
    
    Q_INVOKABLE void joinTournament(const QString& roomCode, const QString& playerJid);
    Q_INVOKABLE void startTournament(const QString& tournamentId);
    
    // --- Match management ---
    Q_INVOKABLE void reportMatchResult(const QString& matchId, 
                                        const QString& winnerJid);
    Q_INVOKABLE void advanceBracket(const QString& tournamentId);
    
    // --- Computer Opponents ---
    Q_INVOKABLE void fillEmptySlots(const QString& tournamentId);
    
    // --- Room codes ---
    Q_INVOKABLE QString generateRoomCode();
    Q_INVOKABLE QString resolveRoomCode(const QString& code);

signals:
    void tournamentsChanged();
    void activeTournamentChanged();
    void matchReady(const QString& matchId, const QString& player1, const QString& player2);
    void tournamentComplete(const QString& tournamentId, const QVariantList& rankings);
    void playerJoined(const QString& playerJid);
};

For filling empty spaces we can use the logic as:

struct Match {
    QString matchId;
    QString player1Jid;   // empty string = unfilled slot
    QString player2Jid;
    QString winnerJid;
    int round;            // 0 = first round, 1 = quarter-finals, etc.
    int position;         // position within the round
    bool isAIMatch;       // true if one/both players are computer
};

class TournamentBracket {
public:
    void initialize(int playerCount);              // builds bracket tree
    void seedPlayers(const QStringList& playerJids); 
    void fillWithAI();                             // fills empty slots
    Match getNextMatch() const;
    void recordResult(const QString& matchId, const QString& winnerJid);
    bool isComplete() const;
    QVariantList getRankings() const;
    
private:
    std::vector<std::vector<Match>> m_rounds;  // rounds[0] = first round, etc.
    int m_totalRounds;
};

At the end of the elimination cycle and the tournament bracket, we can get the results and show them on our created leaderboard page with the XMPP icons, usernames, and the number of games the players won.

What more can be added?

I plan to research more on whether we can store and display these games in the player profiles and create a communication channel for the players and spectators during the ongoing game, which could be both text and voice chat using XMPP and other relevant communication protocols.

Thanks for reading. 👀

Wednesday, 10 June 2026

This is a weekly update from my Google Summer of Code 2026 project with KDE, improving effect widgets in Kdenlive.

Week 2 was about getting feedback and doing it right.

After opening the draft MR for the Curves Widget, my mentor Jean-Baptiste reviewed the approach and suggested a cleaner architecture. The original implementation packed all 4 channel parameters into a single compound parameter. JB's feedback: each channel should be its own separate av_curve parameter in the effect XML, and AssetParameterView should share one CurveParamWidget across all of them; similar to how m_mainKeyframeWidget works for keyframe parameters.

This was a significant refactor but the result is much cleaner:

  • avfilter_curves.xml now has 4 separate parameters; av.master, av.r, av.g, av.b, each with its own name and description
  • AssetParameterView creates the CurveParamWidget on the first av_curve param, then calls addAvCurveTab() for each subsequent one
  • Each tab is tied to its own model index; valueChanged fires per-parameter independently
  • serializeAllChannels() is gone entirely;each channel just emits its own value

All four tabs (All, R, G, B) are working correctly. Per-channel state is preserved when switching tabs. Project save and restore works. The MR is now updated with the refactored approach and waiting for JB's review.

The All tab applies a curve to all channels simultaneously:

Curves widget — All tab

Switching to the R tab adjusts only the red channel independently:

Curves widget — R tab with red tint

Week 3 is already underway; the MR is pushed and waiting for JB's review. More updates next Sunday.

Monday, 8 June 2026

E.P. Unny is a notable Indian political cartoonist, who worked/works with famed Shankar’s Weekly and news papers such as The Hindu and Indian Express.

Since 2020, all his cartoons (also 2025, 2026 so far) are published — every week — open-access by Sayahna Foundation.

Unny was using a font based on his handwriting style for the cartoons, designed by K.H. Hussain of Rachana. Recently, a new font designed by Varshini KVSS & ‘Kandam Collective’ is developed by Rachana Institute of Typography to use in the cartoons, and it is released as open source — see the specimen and download links.

The character set of the font is Latin only. There are plenty of alternate glyphs (for upper case and lower cases of i, j, l, g, etc. — for instance check the double ‘l’ in ‘Intelligence’ on the specimen above). Such characters are rendered alternately to give a feel of the randomness that handwriting evokes.

The source (and issue tracking) are available at RIT fonts repository.

Sunday, 7 June 2026

digiKam 9.1.0 Preview Canvas Displaying an HEIF Photo Taken With Apple 15 Pro

Dear digiKam fans and users,

After three months of active development, bug triage, and feature integration, the digiKam team is proud to announce the stable release of digiKam 9.1.0. This version builds on the foundation of 9.0.0, introducing new features, performance improvements, and a significant number of bug fixes to enhance stability, usability, and workflow efficiency. This release focuses on database migration, preview enhancements, advanced search, and usability improvements across the board.

Saturday, 6 June 2026

The second maintenance release of the 26.04 series is out with the usual batch of bug fixes and improvements for workflow and stability. This update comes with fixes to rendering, timeline editing, project file handling, and Windows, MacOS, AppImage and Flatpak packaging.

One noteworthy bug closed in this version is a fix on Windows to finally allow exporting your videos to a network drive, closing a 4-year-old bug.

Head to our download section to get the latest binaries, or check the updates from your package manager. Please note that for Linux only AppImage and Flatpak are supported by the Kdenlive team.

For the full changelog continue reading on kdenlive.org.

Thursday, 4 June 2026

This week, I completed the port of KeepSecret's actions to the new org.kde.kirigami.actioncollection API from kirigami-app-components, a recently introduced library developed by Marco Martin (notmart).

Before working on this task, actions were defined separately throughout the UI. With ActionCollection, I could define each action once in a central place and then reuse it wherever it was needed. This makes the code easier to maintain and also integrates KeepSecret with KDE's standard shortcut system, allowing users to configure shortcuts through the usual KDE interface.

The main change was creating a dedicated Actions.qml file with AC.ActionCollectionManager as the root element. Inside it, actions are now centrally defined across three collections — one for the wallet list, one for wallet contents, and one for item details. These include actions such as New Wallet, New Entry, Search, Lock, Unlock, Copy Password, Save, Revert, and Delete.

During review, additional actions were added, dependencies were simplified, and Flatpak build issues were addressed. Since kirigami-app-components is still very new, some CI and packaging adjustments were needed before everything built correctly.

The merge request !29 has now been reviewed, approved, and merged into KeepSecret.

Next up is the Import/Export feature — I'll be studying KeepSecret's wallet data structures and designing the file format this week.

Hello Reader!

In case you don't know me (quite likely 😆), I am Ojas Maheshwari (@the_epicman:matrix.org) and I am currently working in the Google Summer of Code program for the KDE community on a project about Font Subsetting in Poppler under my mentor Albert Astals Cid.

Community Bonding

If I am being honest, I had already bonded with the Poppler community before GSoC started 😅

I had a lot of conversations with Albert, Sune, lbaudin and ats, and they already helped me a lot with my technical problems with my contributions prior to GSoC :D

However, I also managed to bond with other fellow GSoC contributors this summer so it's a win in my book :D

Week 1

I learnt a lot about how PDF files work this week.

Technical terms like Indirect Objects, Default Appearance, Appearance Streams which used to sound confusing to me before finally clicked.

I got more comfortable with traversing and using PDF data structures such as Objects, Arrays, Dicts, Streams etc.

The Happy News is that I got the Font Subsetting to work for FreeText Annotations.

I have raised a Draft MR which should be ready-to-review by end of this week and my plan is to get it fully correct and merged first and then move on to doing the same thing for forms.

A picture of my IDE containing my work
Code screenshot to make the blog look cooler

How it works

If you are interested to know what my current approach is:

  • The whole subsetting runs only when the user saves the document.

  • We go over all resources (for now, just FreeText annotations) that were modified, and call a subsetFonts method on them.

  • This is a method implemented by every class that needs subsetting, and inside this method we pass the data on what "font" renders what part of the "text" to our FontSubsetter::getSubsetFonts.

std::map<Ref, Ref> FontSubsetter::getSubsetFonts(const std::map<std::shared_ptr<const GfxFont>, std::string> &fontMappings) const
  • The function generates the subset font objects and adds them to the PDF and returns mappings of old font refs and newer font refs. The subsetting happens using a library called "Harfbuzz".

  • Then the subsetFonts function simply replaces the older refs with the newer ones inside the font subdictionary of the appearance stream of the annotation.

Thanks for reading

Although this blog might look small, it took me more than 1.5 hours to write this because I kept writing and deleting things. I am hoping I get better at writing blogs in the future.

But anyways, thanks for reading!
And have a great day !
Byee 😃!

Luis Cañas Díaz and I shared lessons from our BI journey at the Eclipse Foundation SDV webinar — from open source to automotive. Methodology, real use cases, and hard-won lessons on data, metrics, and insights.

How long does it take for an Item to become visible?

Frames skipped counter in application_QML_Blog_Javier

Frames skipped counter in application

How long does it take for an Item that you’ve just loaded to become visible? Answering this question allows for a way to detect what some users would perceive as "frame drops". I write that in quotes because Qt Quick only draws frames when needed, meaning it doesn't drop frames; but it can show them later than one would expect. That is what we would like to identify: When components are drawn late, and by how many milliseconds or frames are they late?

I've come up with a simple solution - code below the article - on how to measure this. Items being measured must inherit a class based of QQuickItem that has a connection on QQuickItem::visibleChanged. Its visible property should be false by default. When visible becomes true, a slot will start measuring elapsed time and create a direct connection to QQuickWindow::afterFrameEnd. Once the scene graph has submitted a frame, the slot will take the measurement and disconnect the connection that triggered it to prevent further frames from triggering this event.

That alone isn't enough, however. If there were other elements on the scene being animated (say from the render thread via an Animator), those would trigger a frame swap before our item would have had a chance to be drawn, causing our measurement to be taken prematurely.
We need a way of knowing when the frame that draws our component is the one that got swapped into view. Enter QQuickItem::ensurePolished. Calling this function ensures that QQuickItem::updatePolish will be called when the scene graph is ready to render our item. We override QQuickItem::updatePolish and use it to set a flag that’ll tell us that the next frame to come be displayed will correspond to the component we’re measuring. Lastly, we read this flag during the next call to QQuickWindow::afterFrameEnd, effectively using it to trigger the elapsed time measurement only when our item is swapped onto the screen.

There is a variable amount of time between the last user interaction and the moment a frame can be rendered; because of that, a measurement in milliseconds is only accurate to the average time that it takes for one frame to be rendered immediately after the previous frame. That turns out to be 1 second divided by the display's refresh rate. We can use Qscreen::refreshRate, which gives us this value in hertz. For a 60hz display, a frame's time (T) would be 1000 ms / 60 hz ≃ 16 ms. Any time measured that is between zero and T (16 ms) would mean an instant frame swap. If we divide the measured time by T, and apply a floor function to the result, we get the number of frames dropped while making the component visible, which is a more consistent measurement than the number of milliseconds passed. For a well optimized program the output would be zero, one, or a positive integer very close to that. For more information about the rendering process, you can read scene graph and rendering from Qt's documentation.

Make C++ items visible during their instantiation, or they won’t show up on screen. This QQuickItem subclass is different from its parent in that the Item is not visible by default. We set visible to false from the C++ constructor because the order in which initial properties are evaluated and assigned in QML differs depending on the approach used to instantiate the Item and assign its initial properties. You may set the initial visible property of an item in QML to false, then make it true during its instantiation as a delegate somewhere, only for the QML Engine to optimally evaluate its initial value solely to true, causing the visibleChanged signal to never be emitted because there was, effectively, no change to the visible property. Setting the visibility to false from the constructor in C++ is a simple way to guarantee that visibleChanged will be triggered upon any initialization of the visible property in QML.

The code for the QQuickItem subclass described in this article is documented below. Hope you find it useful. Reach out to us if you need help profiling software, would like to receive our training courses, or need help developing tools such as this.

Best regards, Javier

Code

#include <QQuickItem>
#include <QQuickWindow>

class TimedItem : public QQuickItem
{
    Q_OBJECT
    QML_ELEMENT

    Q_PROPERTY(qint64 timeToDisplay READ timeToDisplay NOTIFY timeToDisplayChanged FINAL)

public:
    TimedItem(QQuickItem* parent = nullptr) : QQuickItem(parent),
              m_elapsedTimer(new QElapsedTimer())
{
    setVisible(false);
    // When made visible, measure time to display
    QObject::connect(this, &QQuickItem::visibleChanged, this, &TimedItem::startMeasuringTimeToDisplay, Qt::DirectConnection);
};

qint64 timeToDisplay() {
    return m_timeToDisplay;
};

signals:
    void timeToDisplayChanged();

private:
    void startMeasuringTimeToDisplay()
    {
        if (isVisible())
        {
            // Reset
            m_frameReady = false;
            // Attempt to take measurement after frame swaps
            QObject::connect(window(), &QQuickWindow::afterFrameEnd, this, &TimedItem::measure,
            static_cast<Qt::ConnectionType>(Qt::DirectConnection | Qt::UniqueConnection));
            // Force polish, ensuring elapsed measurement is taken on the right frame
            ensurePolished();
            // Take initial measurement
            m_elapsedTimer->start();
        }
    }

    void updatePolish()
    {
        // The frame for this component will be rendered after this
        m_frameReady = true;
    }

    void measure()
    {
        // This will be called for every frame until the right frame has been rendered
        if (m_frameReady)
        {
            // Measure elapsed time
            m_timeToDisplay = m_elapsedTimer->elapsed();
            // Prevent measuring further frame
            QObject::disconnect(window(), &QQuickWindow::afterFrameEnd, this, &TimedItem::measure);
            // Propagate measured time
            emit timeToDisplayChanged();
        }
    }

private:
    qint64 m_timeToDisplay = 0;
    QElapsedTimer *m_elapsedTimer;
    bool m_frameReady = false;
};

The post How long does it take for an Item to become visible? appeared first on KDAB.

Tuesday, 2 June 2026

When we first announced the transition to Plasma Wayland, one of Martin's slides from stated, "It's done when it's done!"

That talk was 15 years ago!

Nothing in software is never truly "done", but as announced previously we are finally at a point where we're ready to retire the X11 and put all our focus on the future.

As of today, the Plasma X11 session you can log into has been officially removed, and we will start a mass cleanup of X11-specific code soon.

When does it take effect?

This change will be included in Plasma 6.8, which will be released in around five months.

What's Changed?

In Plasma 6.8, there will be no X11 session in the login screen. There will only be a Wayland session available to log into.

In 6.8, all X11-specific code paths in Plasma for Plasma Shell, System Settings, and device configuration will be gone.

What's stayed the same?

XWayland support remains present. You can keep using your X11 applications, and our XWayland application support is second-to-none.

If you use KDE applications on another desktop environment, this change will have no effect. KDE applications will continue to work in X11 for the foreseeable future.

Plasma Login Manager will continue to be able to log you into X11 sessions of other desktop environments.

What's Next?

The possibilities this opens up are very exciting. Until now, on the desktop side, we've had to target the lowest common denominator or be stuck trying to maintain two conflicting code paths. It was absolutely the right choice to do a gradual transition and approach things this way, but that approach has its limits.

Moving forward with a single code path going through Wayland is going to allow us to bring new performance improvements, memory optimisations, and brand new exciting features throughout Plasma.

How Ready Are We?

Our internal metrics within KDE show that over 95% of users of Plasma 6.6 are on Wayland, with a gradual increase every release. The metrics also show that basically no one is testing or developing Plasma on X11 anymore. The platform was already, for all intents and purposes, abandoned by KDE contributors.

We have every reason to trust this metric data, as it is exactly in-line with what Sentry (our automatic crash reporting tool) reports for newly-encountered crashes shows.

For transparency, the one caveat in all of the above is that I've deliberately always focused on people using the latest Plasma release. We do still have a sizable chunk of users on X11 still using Plasma 5.27. Including them, the total Wayland adoption rate is about 76%. But back then, Wayland wasn't the default session type, so it's hardly a surprise those users are still on X11. Things have come a massively long way in the three years since Plasma 5.27 was released.

Anyone still using Plasma 5.27 — or any release older than Plasma 6.8 — won't be affected by what we do in Plasma 6.8, and nothing will be applied retroactively.

Still Have Issues with Wayland on 6.7?

Whilst we have had full confidence since Plasma 6.0 that our Wayland session provides the better overall experience, we are aware that things don't behave exactly the same. Not everything works the same especially in specialised areas.

We are not expecting a completely seamless transition for everyone. Custom scripts, tools used and even workflows might have to change. But we are aiming to offer a transition where there is still a way to accomplish all your day-to-day tasks.

Plasma 6.7 is the last release that will include an X11 session, and it's coming out in just a few days. If you still have issues that force you back to X11 we would love to hear from you.

We can't promise to get everything fixed in time for 6.8, but we can promise to listen and be aware. People's remaining pain point are and will be on our radar, so please take this time to communicate them.