Before writing about my actual Summer of Code experiences, I wanted to briefly share what I worked on before the official coding start.

Plasma Toolicons

Plasma toolicons

Can you see these ridiculously small toolicons next to the Media frame plasmoid? I’m talking about the icons which allow you to Resize, Rotate and Remove the Plasmoid. Compared with other icons, these are clearly too small.

So, as preparation for GSoC, I wanted to know why this happens, and what would be required to make them bigger. Thus my journey into the (Plasma) rabbithole began…

Tracking down where the containment is defined was relatively easy, and shortly after i found the code responsible for the ActionButton:

PlasmaCore.ToolTipArea {
    id: button

    location: PlasmaCore.Types.LeftEdge
    mainText: action !== undefined ? action.text : ""
    mainItem: toolTipDelegate

    //API
    property QtObject svg
    property alias elementId: icon.elementId
    property QtObject action
    property bool backgroundVisible: false
    property int iconSize: 32
[...]

Huh, the iconSize is 32px? Well, that was easy to fix, surely this should be set to units.iconSizes.small and this problem is gone…

… or so I thought. No, this didn’t improve the situation, back to square one.


Is it overwritten by the look and feel theme? plasma-workspace/lookandfeel/contents/components/ActionButton.qml at least doesn’t - and it also happens with the style set to Oxygen.


While looking at this, I also noticed that units.iconSizes.small returned 16px on my system. This seemed odd, because the scale factor was set to 1.8x, so I would have expected bigger icons.

Where is this icon size calculated? Ah yes, in the file units.cpp, method Units::devicePixelIconSize.

int Units::devicePixelIconSize(const int size) const
{
    /* in kiconloader.h
    enum StdSizes {
        SizeSmall=16,
        SizeSmallMedium=22,
        SizeMedium=32,
[...]
     };
    */
    // Scale the icon sizes up using the devicePixelRatio
    // This function returns the next stepping icon size
    // and multiplies the global settings with the dpi ratio.
    const qreal ratio = devicePixelRatio();

    if (ratio < 1.5) {
        return size;
     } else if (ratio < 2.0) {
         return size * 1.5;
     } else if (ratio < 2.5) {
[...]
}

Ok, my devicePixelRatio is 1.8 and therefore the icon size of a small pixmap gets multiplied by 1.5 and a request for a small (16px) pixmap should return a 24px pixmap.

But it doesn’t…

Debugging suggested that my devicePixelRatio is NOT 1.8, but rather around 1.4. How did that happen, isn’t the scale factor from the KDE settings used?


Oh, the comment in updateDevicePixelRatio() mentions that QGuiApplication::devicePixelRatio() is really not used:

void Units::updateDevicePixelRatio()
{
    // Using QGuiApplication::devicePixelRatio() gives too coarse values,
    // i.e. it directly jumps from 1.0 to 2.0. We want tighter control on
    // sizing, so we compute the exact ratio and use that.
    // TODO: make it possible to adapt to the dpi for the current screen dpi
    //  instead of assuming that all of them use the same dpi which applies for
    //  X11 but not for other systems.
    QScreen *primary = QGuiApplication::primaryScreen();
    if (!primary) {
       return;
    }
    const qreal dpi = primary->logicalDotsPerInchX();
    // Usual "default" is 96 dpi
    // that magic ratio follows the definition of "device independent pixel" by Microsoft
    m_devicePixelRatio = (qreal)dpi / (qreal)96;

Hmm, yes, that was the case in earlier Qt versions when devicePixelRatio still returned an integer - but nowadays the value is a real number.

So, instead of calculating dpi / 96 I just changed it to return primary->devicePixelRatio().

Which now, finally, should return a devicePixelRatio of 1.8 and therefore result in bigger pixmaps.

Compiled it, and confident of victory restarted plasmashell… only to notice, that it still didn’t work.


What could there still go wrong?

So I got back to debugging.. to notice that primary->devicePixelRatio() returns a scale factor of 1.0. Huh? Isn’t this supposed to just use the QT_SCREEN_SCALE_FACTORS environment variable, which gets set to the value of the “Scale Display” dialog in the Systemsettings? If you want to know, the code for setting the environment variable is located in plasma-workspace/startkde/startplasmacompositor.cmake.

But why isn’t the problem gone, is there something in Plasma that overwrites this value?


Yes, of course there is!

The only way this value can be overwritten is due to the Qt attribute Qt::AA_DisableHighDpiScaling.

Grep’ing for that one pointed me to plasma-workspace/shell/main.cpp - the base file for plasmashell:

int main(int argc, char *argv[])
{
//    Devive pixel ratio has some problems in plasmashell currently.
//     - dialog continually expands (347951)
//     - Text element text is screwed (QTBUG-42606)
//     - Panel struts (350614)
//  This variable should possibly be removed when all are fixed

   qunsetenv("QT_DEVICE_PIXEL_RATIO");
   QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);

I looked into the mentioned bugs. What should I do now? Re-enabling the HighDpiScaling-flag so the real devicePixelRatio is returned in Qt, and therefore I can use this value to calculate the sizes icons should be and then have the bigger Plasma ToolIcons? At least QTBUG-42606 seems to be fixed…

Oh boy, what have I gotten into now…

It was time to talk to my mentor!


David Edmundson quickly noticed that there should be no mismatch with the dpi / 96 calculation. Something fishy seems to be going on here…

What is this dpi value anyway? This is the one reported by xrdb -query |grep Xft.dpi and managed in the file $HOME/.config/kcmfonts.

And that value - as you probably can guess by now - did not make any sense. It didn’t match the expectation of being scaleFactor * 96, the value it should have been set to.


On we go to the location where the scaling configuration is set - scalingconfig.cpp in the KScreen KConfig Module.

void ScalingConfig::accept()
{
[...]
   fontConfigGroup.writeEntry("forceFontDPI", scaleDPI());
[...]
}

qreal ScalingConfig::scaleDPI() const
{
    return scaleFactor() * 96.0;
}

This scaleDPI is then applied with xrdb -quiet -merge -nocpp on startup.

So Xft.dpi is set to 1.8 * 96.0, or 172.8.

Have you spotted what is going wrong?

I did not, but David noticed…

The X server can only handle real values - and therefore 172.8 is simlpy discarded!

A few moments later this patch was ready…

Plasma Toolicons

… and I was finally able to enjoy my icons in all their scaled glory! And you can too, because this patch is already in Plasma 5.10.