2021-04-28

Programming Language Notes 2021 - multiplatform, GUIs

These are incomplete notes and thoughts on programming languages through lens of multiplatform support and coding GUI apps for platforms like Android, iOS, Mac, Windows, Linux, and web (front and back ends).

JavaScript

Lack type safety.

Java, Go, Python, Ruby, C++, C, Elixir

Not great for frontend web dev.

D

Not great for Android or iOS.   Can build web apps via compiling to WASM (pretty sure it's experimental), but lack mature frameworks for frontend web dev.  Not very popularly used, unfortunately.

TypeScript

It's JavaScript but with a brilliant aftermarket type system retrofit. If you must code JS, then TS is a fantastic upgrade.

For backend, there's faster languages (Java, Go).  For device native apps, other languages are maybe better suited (Swift, Kotlin, etc).  Great choice for web frontend.

For frontend web dev, used with React is popular.  There's React Native to build device native apps for Macs, Windows, Linux, Android, and iOS that uses platform native UI widgets (some haven't reached 1.0 yet though, if you're looking for maturity).  You'd still have to build 5 specialized UIs though (6 including web), and there are faster device native languages.

Kotlin

Compiles to JVM, JS, and native.  Kotlin Multiplatform Mobile (alpha) is great for write-once application logic for iOS / Android native apps, but the UI code must be specialized for each platform (could still be written in Kotlin though).

e.g. Use with Google Android's Jetpack Compose (beta) and Apple's Swift UI for native Android and iOS UI.

e.g. Use with Jetbrains' Compose for Desktop to build apps for Windows, Macs, and Linux --- but this  runs on JVM and renders using Skia, so it doesn't use platform native UI widgets (it draws it's own like a game does).  And it's in alpha.

Some say Jetpack Compose is Google Android team's answer to Google Ads team's Dart/Flutter.

Kotlin/JS means you can use with React for frontend web dev too.  Not sure of its maturity.  Kotlin is great for backend using Spring or Ktor.

PHP

Not great for device native apps

C#

Windows centric.  Blazor lets you do frontend web dev by compiling to WASM but it adds C#'s runtime to your web app to run in WASM as well (read: bigger, slower app).

Rust

Lower level, like C or C++.  Can build web apps via compiling to WASM, but without bringing a runtime along for the ride (check out Yew or Seed).  Can build backend stuff (check out Actix-web or Rocket), but frameworks aren't mature the way Django or RoR are.

Coding device native GUI apps is... not there yet.

Rust is getting a lot of traction for systems programming though (unlike D, unfortunately).

Dart

Basically exists for Flutter.  Flutter lets you build apps for Windows, Macs, Linux, iOS, Android, and the web.  On the web, it draws into a canvas.  On devices, it renders using Skia.  So it doesn't use platform native UI widgets anywhere, and draws it's own like a game does.  On the web, it's UI performance is a little janky.

Dart compiles to JS or runs on Dart VM.  Unlike the Kotlin stuff above, Flutter is production ready and being used by Google, notably by their Ads team (apparently some of the Kotlin stuff above are the Android team's answer to Flutter).

It's from Google, so who knows if they'll cancel it in 5 years time.

Other thoughts

Rendering to Skia like Compose for Desktop and Flutter is not great for accessibility, and their accessibility features are currently WIP.

React Native has edge cases for each platform so you'd still need to know each platform carefully.  Plus TypeScript / JavaScript bridging into native can have performance issues.

 Nothing's perfect.

That's all I've got time for today!

Missing: Scala, Clojure, Haskell, F#, Crystal, PureScript, Elm.

2021-03-25

Use ISO 8601 dates in PCManFM on Debian LXQt

I like ISO 8601 or RFC 3339 style dates.  That is, rather than "January 15, 2021", I like "2021-01-15".

This is especially useful in a file manager, having all the year-month-day lined up vertically in a column.

I also prefer 24-hr time format for the same reason.  But how to set this up?

 

macOS Finder

For Mac's file manager, it's really easy to set the date/time format:

Just open System Preferences > Language & Region > Advanced > Dates, then modify the date formats to whatever you want.  At the same time, you could go to the Times tab and set it to use 24-hr format. 

Done!  I offer this as just a point of comparison for what's below...


Debian LXQt PCManFM

On LXQt's PCManFM file manager, running on Debian, the setup was... annoyingly difficult.

PCManFM does not allow custom date/time formatting.  It only respects the system set locale.  So you have to choose the right locale.

Step 1.1: Select Locale

On LXQt, you can easily set the locale (they call it "Region") by running lxqt-config-locale in the terminal, or else click the system Preferences > LXQt settings > Locale.

Step 1.2: Which locale to choose???

You have a number of options.

Do you want:

  • English language
  • dollar denominated
  • metric
  • ISO-8601
  • but 12-hr time?

Use Canadian English (en_CA) locale.

If that's not close enough, and you really want 24-hr time as well, you can enable Detailed Settings and change the Time locale to Sweden - English (en_SE).

Be sure to see Step 2: Installing Locales in Debian, because chances are doing the above will cause system errors later!

Note that en_CA uses Canadian dollars, not USD!  You can change the Currency locale to American English (en_US) if you want real USD dollars.  Although it probably doesn't matter for formatting purposes.

Why Sweden?  It turns out lots of Europeans want something similar, as in a locale that is English language, metric, using ISO-8601 or similar style dates!

Sweden - English is an unofficial locale made up to give us that [1], but it does use Swedish kronor SEK for currency [2].  That's why you only want to set the Time locale to use en_SE, keeping the rest as en_CA (or en_US).

 

Step 2: Installing Locales in Debian

Selecting the "Region" in LXQt's locale preference app is just half the story.

PCManFM will probably work fine as is.  Qt apps are fine because it uses it's own Qt locale definition lookup system, and includes en_CA and en_SE by default.

Debian does not include en_CA by default, so you'll have to install it.  And it does not have en_SE... not at all... you'll have to add the en_SE definition file manually then install it.

You can download a copy of the en_SE locale definition written by Mikael Auno [7].  Then create this directory if it doesn't exist:

/usr/local/share/i18n/locales

Place the en_SE file into the above locales directory.  Create a text file in the above i18n directory containing this text:

en_SE.UTF-8 UTF-8

Then run in terminal:

$ sudo dpkg-reconfigure locales

You should see a list of locales you can install.  Look for and install the ones you selected in LXQt's locale preference app.  For my example above, that means en_CA, en_US, and en_SE.

Lastly, logout and re-login for the changes to take effect.

 

Fully Custom Locales in Debian: don't bother

From above, you see Debian allows you to create totally custom locales, so you can customize all the formats the way Macs can!  After all, that en_SE locale file you downloaded was just made up so to speak, and you can customize it however you want.

...but Qt won't use it.  Qt's locale system runs parallel to Debian Linux's.

So why go through the trouble of installing the en_SE locale if Qt won't use it?  Because if you don't, you'll run into problems with non-Qt apps, problems like:

Run locale in the terminal, and it'll complain:

locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

Unzip certain archives using file-roller results in a dialog box complaining:

An error occurred while extracting files.
Pathname can't be converted from UTF-8 to current locale.

That occurs because a locale you chose in LXQt was not installed in Debian [8].  Qt is perfectly happy though, as it runs a separate locale system...

 

Firefox locale incompatibility

If you set your locale to Canadian or US English (en_CA or en_US), and enabled Detailed Settings to change the Time locale to Sweden - English (en_SE), Firefox will show numbers in Swedish / European style, like "3,14" instead of "3.14".

This problem happens at least in the downloads window.

Method 1: Fix by setting LC_ALL environment variable

The most reliable way to fix it in Debian is to set the LC_ALL environment variable, but only for Firefox [13].  Don't set LC_ALL globally or it'll undo the locale changes above, plus you just shouldn't as it overrides everything [12]. 

For the terminal :

With that said, all it involves is opening Firefox in the terminal like this:

LC_ALL=en_CA.utf8 firefox

You can save that in a script that's in your PATH so running Firefox always uses the LC_ALL locale.

For the Firefox icon:

The Firefox icon in Debian requires a different fix though.  That icon in the applications menu is controlled by a  firefox.desktop file located at:

/usr/share/applications/firefox.desktop  

You can modify it directly or, safer, copy it to your user's applications folder:

~/.local/share/applications

Once copied, open it in a plaintext editor and change the Exec line to this:

Exec=sh -c "LC_ALL=en_CA.utf8 /usr/bin/firefox"

 

Method 2: Fix by setting Firefox locale internally

The "official" way to set the Firefox user interface locale is via Firefox's preferences [14]:  open preferences, then go to the Language section of the General panel.

I've tried it on Debian and it doesn't work.

You could also try finding in about:config the intl.locale.requested key and set it to the desired locale [15].  I didn't test this method though because setting the LC_ALL environment variable worked perfectly for me.


Other locale options

Sweden - English (en_SE) is an unofficial locale made up to give us English language, metric, ISO-8601 date format [1].  But it uses Swedish kronor SEK for currency [2].

Denmark - English (en_DK) is another unofficial locale made up with similar English and metric formats [3].  But the date is backwards (in dd/MM/y format), and uses Danish kroner DKK currency [4].

Ireland - English (en_IE) is an official locale that, like Denmark - English, gives us English and metric units [5], and like en_DK, the date is backwards (in dd/MM/y format).  It uses Euro for currency [6] though.

So by mixing and matching Ireland, Denmark, and Sweden, you should be able to get a reasonable ISO 8601/English/Euro(pean) locale.

And mixing Canada, US, and Sweden will get you a reasonable ISO 8601/English/Dollar locale.


References

[1]: https://unix.stackexchange.com/a/62318

[2]: https://icu4c-demos.unicode.org/icu-bin/locexp?d_=en&_=en_SE

[3]: https://unix.stackexchange.com/a/272665 and https://superuser.com/a/1269909

[4]: https://icu4c-demos.unicode.org/icu-bin/locexp?d_=en&_=en_DK

[5]: https://unix.stackexchange.com/a/62317

[6]: https://icu4c-demos.unicode.org/icu-bin/locexp?d_=en&_=en_IE

[7]: https://bugs.launchpad.net/ubuntu/+source/langpack-locales/+bug/208548/comments/11

[8]: https://unix.stackexchange.com/a/269293

[12]: https://wiki.debian.org/Locale#Configuration 

[13]: https://unix.stackexchange.com/questions/34965/how-to-change-firefox-language#comment47453_34967

[14]: https://support.mozilla.org/en-US/kb/use-firefox-another-language?redirectslug=use-firefox-interface-other-languages-language-pack&redirectlocale=en-US#w_how-to-change-the-language-of-the-user-interface

[15]: https://support.mozilla.org/en-US/questions/1223719#answer-1127761


Bibliography

[9]: https://github.com/lxqt/pcmanfm-qt/issues/656

[10]: https://github.com/lxqt/lxqt-config/issues/507

[11]: https://wiki.debian.org/Locale


2021-03-18

Enable 3 Finger Drag on Linux

3 Finger Drag (3FD) is not available on Windows, and not built-in on Linux

On Windows, we can achieve something similar.  Let's call it:  3 Finger Tap to Drag Lock.  See Enable 3 Finger Drag on Windows for how.

On Linux, it is apparently possible to have pretty good 3 Finger Drag!  See below.

Pretty good but not as good as Mac's 3FD, but without Apple's tightly integrated hardware, software, OS, driver, etc., it's impossible to get Apple Mac's high quality 3FD.

What's 3FD anyway?

3 Finger Drag refers to a Mac accessibility feature.  When enabled, if you place three fingers on the Mac's trackpad or touchpad, then move those fingers in unison on the trackpad, the mouse pointer behave as if you left-clicked-and-are-dragging.

It's a better more ergonomic alternative to the tap-twice-and-drag method that's common on Macs, Windows, and Linux.

It's better because there's less finger tapping movement which can develop into "trigger finger" type repetitive strain injury.  If you drag things around a lot, tap-twice-and-drag plus another tap to deactivate dragging starts to add up to being a nuisance!

And at least for me, when dragging using the  tap-twice-and-drag gesture, I often have trouble continuing to drag mid-drag if I lift my hand away from the trackpad to reposition.  And ironically, I also have trouble disengaging the drag once I've reached the target of the drag motion too!

How to add 3FD to Linux

As of 2021 January, the happy path to getting 3FD on Linux is:

  1. Use a desktop Linux system that uses libinput for handling the trackpad
  2. build your own custom 3FD enabled libinput
  3. install your custom libinput.

(1) Use a desktop Linux system that uses libinput for handling the trackpad

Fortunately, Ubuntu and Debian uses libinput.  And libinput works with both Wayland and X11.  And Gnome/Xfce/KDE/LXDE all work with libinput.  So practically everyone's standardized onto libinput for trackpad and gesture support in 2021!

(2) Build custom 3FD enabled libinput

Unfortunately, 3FD isn't standard in libinput.  And likely won't be for a very long time if ever.

But there's a patched version of libinput with 3FD added!  Here's the most recent patch:  aakside's libinput.

(3) install your custom libinput

See Dakshin Karthikeyan's article for the Linux specific instructions on how to install.

Caution: Dakshin's article references a different 3FD patched libinput that's by jafd, which is slightly older and apparently with less 3FD enabling features.

To be clear, aakside's 3FD enabled libinput is a rebasing of complyue's 3FD libinput patch onto a more updated libinput.

I wrote a State of Built-in 3 Finger Drag on Linux post earlier if you want to understand more the relationship between the various libinput patches / forks.

2021-03-10

State of Built-in 3 Finger Drag on Linux

 Will we ever get built-in 3 Finger Drag (3FD) on Linux?  At this point, likely not.

Non-libinput desktop Linux

For older desktop Linux not using libinput for trackpad support, you can look into mtrack (no 3FD but...) and the p2rkw's mtrack fork which provides 3FD.  Marty's article [1] is older but explains it well for non-libinput desktop Linux.

But non-libinput is on the way out.

Libinput is basically standard in 2021

Everyone's using libinput now, pretty much.  If you're on a desktop Linux machine using Wayland, you're using libinput.

If you're using X11 still, you still could be using libinput.  Or synaptics or xf86-input-* or...  but at least on Debian buster LXDE as I am, turns out it's using libinput.

Libinput sits between your input drivers in the linux kernel and the display server.  Libinput is the present and future of gesture, event, and pointer support for trackpads on Linux.

So if you want 3FD into the future, we have to look at libinput.

Configuring libinput

If you're using Wayland on Linux, there's no way to configure libinput.  This is by design.  You should use your desktop environment's configuration to configure the trackpad.  Your desktop environment will configure libinput as needed.

Using X11 on Linux, you can still configure libinput.  Like most things X11 related, you have to change configuration files here and there.  See libinput's FAQ on this point to start.  But ArchWiki's libinput page is great with plenty of details.

There is, however, no configuration for 3FD for libinput anyway.

State of 3FD support in libinput via patches

There's two patched versions of libinput with 3FD added you could try!

  1.  jafd's libinput 
  2. aakside's libinput --- this is an updated version of complyue's libinput which had 3FD enabled but was based on an older libinput version

See Dakshin Karthikeyan's article for the Linux specific instructions on how to install.  But Dakshin references jafd's libinput instead of complyue / aakside's patch.

 If you go through the whole Request for three fingers click+movement in libinput's repository, you'll see that jafd's 3FD is possibly less featureful than complyue's.  But complyue's version was based on an older libinput.

That Request discussion thread also seems to point at the difficulty and possibly impossibility of libinput ever having 3FD enabled by default.

Fortunately, aakside updated complyue's patch to the latest libinput!

 

References

[1] 3-finger-drag on Linux

2021-03-04

.bashrc, .profile, .bash_profile in Lubuntu vs Debian LXDE

Here we go again... profile vs bash_profile vs bashrc dot files.

In Lubuntu

I had figured previously [1] that:

  • Desktop environment's graphical login sources .profile
  • bash started in login mode sources .bash_profile, but if that doesn't exist, then falls back to sourcing .profile
  • bash started interactively (hence in non-login, or interactive, mode) sources in .bashrc only
  • Both .bash_profile and .profile should contain code to source in .bashrc

So when does code in each file run?

.profile has code you want to run only once, and only upon your DE graphical login.

.bash_profile has code you want to run once only upon your bash shell executing in login mode

.bashrc has code you want to run every single time bash starts, or when you login (if .profile sources in .bashrc as it should), or when bash starts in login mode (if .bash_profile sources in .bashrc as it should).

In Debian LXDE

It seems that:

  • Desktop environment's graphical login AND bash started in login mode both source .bash_profile, but if that doesn't exist, then falls back to sourcing .profile
  • bash started interactively (hence in non-login, or interactive, mode) sources in .bashrc only
  • .bash_profile or .profile should contain code to source in .bashrc
  • You should not have both .bash_profile and .profile since then the latter will be ignored anyway

This meant there's no place to put code that you want to run only once, and only upon your DE graphical login.

The workaround is to put the code in .profile (and you shouldn't have .bash_profile around as it'll override .profile).

Then make that code run only if the GUI is running, which you can detect.  And also make the code only once only, by checking if it's run before.

e.g. in .profile


if [ -n "$DISPLAY" ]; then
    if [ ! -n "$RUNONCE" ]; then
        export RUNONCE="done" # like a C include guard
        cat "GUI running" > GUI_is_running.txt
    fi
fi 

In a console without a GUI, $DISPLAY is not defined.

To learn more

 Some resources from other sites:

[1] profile bash_profile bashrc on Ubuntu Linux, Macs, and Windows