Programming in C#, Java, and god knows what not

Renaming Master Branch to Main

Illustration

GitHub is making a major change to the default branch name. As of October 1st, the default branch will be called main instead of master. While this is done just for the new repositories and the official recommendation is to wait until the end of year for the existing ones, I was never the one to follow the rules.

To locally change the name of the branch, you just need to move it.

git branch -m master main

Next step is telling GitHub you have a new branch:

git push -u origin main

If you go to GitHub now, youl’ll see both main and master present with master still being the default. To change this you’ll need to go into the repository settings and switch default branch there.

Only once that step is done, you can delete master branch forever.

git push origin --delete master

Now the existing repository now has main as the default branch name.

As you can see, currently this process is a bit involved and I am sure that GitHub will automate it reasonably soon. You might want to wait with local renames until they do. My plan is to update branch names as I push updates to my projects. Active repositories will get the update sooner while some old repositories might stay with master forever.

That’s all fine and dandy but what about the new repositories? Well, there’s a setting for that too. Just adjust init.defaultBranch Git property.

git config --global init.defaultBranch main

And now you’re ready to roll.


PS: I will not get into politics whether this change was necessary or not. As a Croat, I will never fully understand the slavery and the emotional impact having the master branch might have. For me this change is more of pragmatism. The exact name doesn’t matter much to me and main is a better choice anyhow.

On-screen Measurement Grid

Illustration

When shopping for gloves it is really useful to know hand size. Normal person would find a measuring tape. Me? I decided to make a on-screen measurement grid.

First step is just figuring pixel dimensions in relation to my diagonal. A bit of Pythagorean later, the following proved to be what I needed:

var diagonal = 15.6;
var pixelWidth = 1920;
var pixelHeight = 1080;

var ratio = 16.0 / 9;
var height = diagonal / Math.Sqrt(ratio * ratio + 1);
var width = height * ratio;  // not really needed

var pixelsPerInch = pixelHeight / height;

var inchWidth = pixelWidth / pixelsPerInch;
var inchHeight = pixelHeight / pixelsPerInch;

Notice here that I am using “witchcraft” units instead of millimetres as I normally would. Reason for that is simple - I was buying gloves on USA site and all measurements were in inches. My screen measurement was also in inches. With both these units being the same, it made no sense to convert into something else first.

Also notice I am only using height to determine pixel density thus making an assumption pixel is a perfect square. Unless you are dealing with something really strange, this assumption is perfectly good.

With these basic calculations done, it’s time to draw. Notice I have a few multiplications/divisions by 4 hear - the only reason for these is due to me finding inch-based grid way too coarse. A quarter-inch grid gives a bit more flexibility here.

using (var bmp = new Bitmap(pixelWidth, pixelHeight))
{
    using (var g = Graphics.FromImage(bmp))
    {
        g.FillRectangle(Brushes.White, 0, 0, pixelWidth, pixelHeight);

        for (var i = 0; i < (int)Math.Ceiling(inchWidth) * 4; i++) {
            var pen = (i % 4 == 0) ? Pens.Black : Pens.LightBlue;
            var x = (int)(i / 4.0 * pixelsPerInch);
            g.DrawLine(pen, x, 0, x, pixelHeight);
        }

        for (var i = 0; i < (int)Math.Ceiling(inchHeight) * 4; i++)
        {
            var pen = (i % 4 == 0) ? Pens.Black : Pens.LightBlue;
            var y = (int)(i / 4.0 * pixelsPerInch);
            g.DrawLine(pen, 0, y, pixelWidth, y);
        }
    }
    bmp.Save("Background.png");
}

I made this image my background and voila! Now I can measure my hand without ever leaving my chair.

Dark Mode for QT Application

With dark mode becoming quite fast the default setup for many, I figured having it in the new QText wouldn’t hurt. And with QT it’s easy - surprisingly so. Just start with a good style (i.e. Fusion) and adjust its palette. And that’s all it took.

qApp->setStyle(QStyleFactory::create("Fusion"));

QPalette newPalette;
newPalette.setColor(QPalette::Window,          QColor( 37,  37,  37));
newPalette.setColor(QPalette::WindowText,      QColor(212, 212, 212));
newPalette.setColor(QPalette::Base,            QColor( 60,  60,  60));
newPalette.setColor(QPalette::AlternateBase,   QColor( 45,  45,  45));
newPalette.setColor(QPalette::PlaceholderText, QColor(127, 127, 127));
newPalette.setColor(QPalette::Text,            QColor(212, 212, 212));
newPalette.setColor(QPalette::Button,          QColor( 45,  45,  45));
newPalette.setColor(QPalette::ButtonText,      QColor(212, 212, 212));
newPalette.setColor(QPalette::BrightText,      QColor(240, 240, 240));
newPalette.setColor(QPalette::Highlight,       QColor( 38,  79, 120));
newPalette.setColor(QPalette::HighlightedText, QColor(240, 240, 240));

newPalette.setColor(QPalette::Light,           QColor( 60,  60,  60));
newPalette.setColor(QPalette::Midlight,        QColor( 52,  52,  52));
newPalette.setColor(QPalette::Dark,            QColor( 30,  30,  30) );
newPalette.setColor(QPalette::Mid,             QColor( 37,  37,  37));
newPalette.setColor(QPalette::Shadow,          QColor( 0,    0,   0));

newPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127));

qApp->setPalette(newPalette);

PS: Ok, chances are that you will need another iconset but that’s the story for some other time.

SignTool Failing with 0x80096005

After creating a new setup package I noticed my certificate signing wasn’t working. I kept getting error while running the same signing command I always had.

sign -s "My" -sha1 $CERTIFICATE_THUMBPRINT -tr ^^http://timestamp.comodoca.com/rfc3161^^ -v App.exe
 SignTool Error: An unexpected internal error has occurred.
 Error information: "Error: SignerSign() failed." (-2146869243/0x80096005)

A bit of troubleshooting later and I narrowed my problem to the timestamping server as removing /tr option made it work as usually (albeit without the timestamping portion). There were some certificate changes for the timestamp server but I don’t believe this was the issue as the new certificate was ok and I remember their server occasionally not working for days even before this.

And then I remembered what I did the last time Comodo’s timestamp server crapped out. Quite often you can use other, more reliable, timestamp server. In my case I went with timestamp.digicert.com.

sign -s "My" -sha1 $CERTIFICATE_THUMBPRINT -tr ^^http://timestamp.digicert.com^^ -v App.exe
 Successfully signed: App.exe

PS: This same error might happen due to servers refusing SHA-1.

Fixing Git Author Name and Email

After moving Mercurial repository to Git you might want to update user names and emails.

The first step would be to see the all the names:

git log --format='%an <%ae>' | git log --format='%cn <%ce>' | sort | uniq

With this information in hand, we can adjust names with filter-branch:

git filter-branch --force --commit-filter '
    OLD_NAME="^^unknown^^"
    NEW_NAME="^^My name^^"
    NEW_EMAIL="^^myemail@example.com^^"
    if [ "$GIT_AUTHOR_NAME" = "$OLD_NAME" ]; then
        GIT_AUTHOR_NAME="$NEW_NAME"
        GIT_AUTHOR_EMAIL="$NEW_EMAIL"
    fi
    if [ "$GIT_COMMITTER_NAME" = "$OLD_NAME" ]; then
        GIT_COMMITTER_NAME="$NEW_NAME"
        GIT_COMMITTER_EMAIL="$NEW_EMAIL"
    fi
    git commit-tree "$@";
' --tag-name-filter cat -- --branches --tags --all

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin

Using TLS 1.3 from .NET 4.0 Application

Due to ubiquitous support for .NET 4.0 on all Windows platforms (including Windows 10) out-of-box, I still keep most of my freeware apps on it. Yes, I lose some new fancy features but not dealing with .NET Framework download makes it really convenient. But there is one thing that proved to be a problem - TLS 1.3.

When I changed my web server to use only TLS 1.2 and above, built-in upgrade suddenly stopped working. Digging a bit showed reason was that .NET 4.0 supported only TLS 1.0 by default and my web server where upgrades were located required TLS 1.2 at the minimum.

For the latest .NET versions, updating to a higher TLS is easy enough:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13
                                     | SecurityProtocolType.Tls12
                                     | SecurityProtocolType.Tls11
                                     | SecurityProtocolType.Tls;

But Tls11, Tls12, and Tls13 enums are not part of .NET 4.0. However, because .NET is so closely integrated with Windows, sometime it’s worth asking it directly - by specifying enum’s numerical value:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)12288
                                     | (SecurityProtocolType)3072
                                     | (SecurityProtocolType)768
                                     | SecurityProtocolType.Tls;

If you run this code before making the first HTTP request, suddenly you are not limited to the SSL and the ancient TLS anymore.

As this code still requires a bit of error checking, I finally ended up with the function below:

try { //try TLS 1.3
    ServicePointManager.SecurityProtocol = (SecurityProtocolType)12288
                                         | (SecurityProtocolType)3072
                                         | (SecurityProtocolType)768
                                         | SecurityProtocolType.Tls;
} catch (NotSupportedException) {
    try { //try TLS 1.2
        ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072
                                             | (SecurityProtocolType)768
                                             | SecurityProtocolType.Tls;
    } catch (NotSupportedException) {
        try { //try TLS 1.1
            ServicePointManager.SecurityProtocol = (SecurityProtocolType)768
                                                 | SecurityProtocolType.Tls;
        } catch (NotSupportedException) { //TLS 1.0
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
        }
    }
}

This code ensures the highest TLS is supported even from the poor old .NET 4.0.

Unique Machine ID

Every once in a while I need to uniquely identify a machine. I don’t case about its name or properties. I just want something unique to key off and ideally I want its format to be the same on both Windows and Linux.

On Linux you can use content of /etc/machine-id. On pretty much all distributions I’ve tried this file will be generated on install and will contain UUID. For Windows, one must look in Registry. Under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid Windows will keep their unique identifier also in UUID format (albeit with dashes this time).


PS: Note these values can be manually changed by user so you cannot really depend on them for security purposes (e.g. generating licenses). But for machine identification they’ll do.

Adding Space Before Equals in Git Prompt

I like using Git-Prompt to decorate my bash prompt. It’s nice, simple, and it would be perfect if it didn’t put equals next to branch name. Not sure what I’m talking about?

If you have modified files, Git-Prompt will make sure to let you know by writing master %= in prompt line. If you want to quickly copy branch name, you simply double click it and only master is selected. However, when there are no modifications to Git tree, output will be master=. Notice the lack of space. When you double click on this, both branch name and equals sign get copied. What I want is to have a space no matter whether branch is modified or not.

Cause for this issue can be found in the following line

local gitstring="$c$b^^${f:+$z$f}^^$r$p"

This makes it for that extra flags get space. If there are no flags, there is no space. Solution is simple - just add space always thus changing line like this:

local gitstring="$c$b$z$f$r$p"

Or, if you like to do it programmatically:

sed -i 's/local gitstring=.*/local gitstring=$c$b$z$f$r$p/' ~/.git-prompt.sh

PS: If you are wondering, this is how my prompt setup looks:

LC_COLLATE=C

if [ -f ~/.git-prompt.sh ]; then
    GIT_PS1_SHOWDIRTYSTATE=true
    GIT_PS1_SHOWSTASHSTATE=true
    GIT_PS1_SHOWUNTRACKEDFILES=true
    GIT_PS1_SHOWUPSTREAM="auto"
    GIT_PS1_STATESEPARATOR=" "
    GIT_PS1_DESCRIBE_STYLE="default"
    GIT_PS1_SHOWCOLORHINTS=true
    GIT_PS1_HIDE_IF_PWD_IGNORED=
    . ~/.git-prompt.sh
fi

function ps1_timer_start {
    PS1_TIMER=${PS1_TIMER:-$SECONDS}
}

function ps1_timer_stop {
    PS1_TIMER_VALUE=$(($SECONDS-$PS1_TIMER))
    if [[ $PS1_TIMER_VALUE -eq 0 ]]; then
        PS1_TIMER_VALUE=""
    elif [[ $PS1_TIMER_VALUE -lt 60 ]]; then
        PS1_TIMER_VALUE=" ${PS1_TIMER_VALUE}s"
    else
        PS1_TIMER_VALUE=" $((PS1_TIMER_VALUE / 60))m$((PS1_TIMER_VALUE % 60))s"
    fi
  unset PS1_TIMER
}

trap 'ps1_timer_start' DEBUG
PROMPT_COMMAND=ps1_timer_stop

PS1='\[\e[36m\]\n\u@\h\[\e[0m\] \w\[\e[34m\]$PS1_TIMER_VALUE\[\e[37m\] \[\e[36m\]\[\e[7m\]`__git_ps1 " %s "`\[\e[0m\]\n\[\e[36m\]\\$\[\e[0m\] '

Bimil failing with FontFamilyNotFound

While Bimil is primarily Windows application, I use it regularly on Linux. However, when I tried running it on freshly installed Linux Mint 19.3, I was greeted with a quick crash.

Running it from console did shine a bit more light onto the situation as the following line was quite noticeable: [ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: The requested FontFamily could not be found [GDI+ status: FontFamilyNotFound].

As mono is Windows Forms application written in C#, running it on Linux requires a few packages extra. Most of them are actually taken care of with the installation of mono-complete. However, in Linux mint, I found one other dependency I was not aware of - Microsoft fonts.

Solution?

sudo apt-get install ttf-mscorefonts-installer

Gray Background for Read-Only QLineEdit

Setting a text box (aka QLineEdit) to read-only in QT doesn’t make its background gray as one would normally expect. Background remains as is with user confused as to why text cannot be changed. Classic Windows solution of graying out background seems much better to me and I decided to replicate the same.

My requirements for this were just two. It had to work correctly under both Windows and Linux. And it couldn’t use static color but follow the overall theme.

The first idea was to use background role.

ui->lineEdit->autoFillBackground(true);
ui->lineEdit->setBackgroundRole(QPalette::Window);

And, even with background auto-filling set, this doesn’t work.

As I was after the same color as window background, setting the whole text box transparent seemed at least plausible.

ui->lineEdit->setStyleSheet("background: transparent;");

This sort-of worked but with only top border-line visible instead of full rectangle. Passable but ugly.

After a few more false starts, I finally found code that fulfills both requirements.

QPalette readOnlyPalette = ui->lineEdit->palette();
readOnlyPalette.setColor(QPalette::Base, ui->lineEdit->palette().color(QPalette::Window));
ui->lineEdit->setPalette(readOnlyPalette);

Essentially, we modify palete and set it’s color to what Window would use. A bit more involved than just setting read-only property but I guess not too difficult either.