How to make the cross-platform Windows Manager in 50 Days.
The post is about my journey on how to create a cross-platform application.
Table of contents
- The Original Idea
- Side project
- Here's how it all began. The First Week.
- The Second Week. Keep improving infrastructure. Development under Windows.
- The Third Week. Native NodeJS modules for all Operating Systems.
- The CI/CD or the fourth week plus new features and 🐞 for SMBAct
- Week 5. Signature and Legalisation time. Unexpected problems.
- Week 6. Bugs. AWS s3. Death of Ubuntu. Apple Notarization. Final steps in pipelines. Covid.
- Final Week and Day 50.
- Final thoughts
The Original Idea
I have been working as a developer for many years. Besides that, I have worked on plenty of my side projects. Roughly 50 days ago. I decided to document the whole process. What, when, where, and how I do several things. I posted a tweet every day and this post is the summary of my journey. This post describes 50 of 100 days in the 100 Days of Code Challenge.
Writing and committing code every day for 50 days is extremely difficult.
I started working on a new side project at the end of January 2023. The idea was to reuse one of my cross-platform libraries and wrap it into the application. As a result, the SMBAct All-in-one cross-platform window manager and switcher was born.
Side project stack
I have used ElectronJs, Typescript, Angular, ObjectC / C++ (nodejs native modules), Groovy for Jenkins, Java Spring for a simple license server, and PostgreSQL to store some license information.
Here's how it all began. The First Week.
Looking back at the Twitter timeline, everything started from the bug on MacOS 😁. I have tested it on four Macs. Three Macbook Pro were working correctly but on a Mac Mini, the was an issue with moving and resizing Chrome. I had to install XCode and inspect the Swift code and carefully adapt my library on ObjectC. As a result, small changes and calls of Mac Accessibility API fixed the issue.
The next day, I switched to the implementation of an offline license check. The license key is a JWT token. The license check does not require a permanent internet connection. The Cryptojs library works perfectly here.
Day four was not devoted to SMBAct either. Finally, I split the test and production servers for the main website. I adjusted the deploy script and Groovy pipelines. For the deployment, I use Ansible in the docker. The Groovy pipeline calls commands against the docker container and the deployment goes smoothly. This is a widely-used approach that enables system deployment to be agnostic.
Day five revealed the amazing feature: “Hide windows on all displays or/and the active/main display.”
On the sixth day, I was working on my website. I realized that people visit my website from my Twitter profile. As a result, I decided to deploy a new version of yesakov.com (GoHugo and Tailwind).
I spent the last day of the first week working on the automatic deployment of yesakov.com and smbact.com. It is a crucial part of every product. Investing time, in the beginning, will save a tremendous amount of hours afterward. Ansible, docker, and groovy pipelines help me here.
Below there are several screenshots from the first week:
The Second Week. Keep improving infrastructure. Development under Windows.
In the first half of the second week, I kept working on the automatic deployments of all websites and started implementing a single proxy for the Paddle payment webhook. I want to keep all products in one paddle account. Unfortunately, Paddle does not provide different webhooks for different products. This proxy has been implemented in Java and Spring. It uses the Spring Cloud gateway to proxy requests. It is dockerized and successfully deployed. Again, here Ansible and Groovy helped me. PostgreSQL is used to store the license requests.
In the second half of the week, I started fixing bugs in SMBAct. At the end of the week, I switched to Windows dedicated environment and started working on the native nodejs module of SMBAct for the Windows operating system. My Jenkins has a lot of different agents: Linux, Headless Mac, and Windows. This time I was able to connect a Windows 10 agent via SSH. It eased my life. Windows has become very user-friendly for people who get used to working with *nix systems. The OpenSSH server on Windows comes almost out of the box.
My final thoughts are:
The WinApi is the most friendly I have ever seen in comparison with X11 Linux and MacOS Accessibility API.
The first time I faced WinApi was in 1999. Almost nothing has changed for the last 20+ years.
I would say one thing became worse. It is Microsoft documentation. Honestly, I have missed the time of the MSDN CDs. As a result, I used ChatGPT as the documentation for WinApi.
Below there are several screenshots from the second week:
The Third Week. Native NodeJS modules for all Operating Systems.
The whole week was devoted to SMBAct development. It took some time to develop the required native functionality under Windows. Also, SMBAct got the support of the portrait display orientation.
After the implementation of the Windows Management functionality for all major operating systems, I can say:
The best Window Fullscreen functionality is in Linux. Windows and Mac are not good here.
Integrated Window Manager in Windows is awful (This is one of the reasons why I started working on SMBAct).
Windows predefined Hotkeys cannot be overwritten (As usual Microsoft knows better what you need and what you have to use).
Looks like nothing has changed in the last 20 years. Visual Studio remains the best debugging tool for C++ on Windows.
On one of the community websites I got positive feedback 🤩. I do believe that I develop a tool "From developers, for developers".
The third-week screenshots are here:
The CI/CD or the fourth week plus new features and 🐞 for SMBAct
I have already mentioned that I use Jenkins as a code to build all projects/products I develop.
The week started with preparing a new virtual machine with Windows. I created a new instance. Afterward, I added it to Qemu on Ubuntu and performed the necessary steps such as Visual Studio Installation, Git, OpenSSH server, etc. On the Ubuntu host, I created port-forwarding rules and added a new Windows Jenkins agent.
I adapted the Groovy pipeline for macOS, Linux, and Windows and got CI/CD work for all native modules.
SMBAct is the Electron Application written in Typescript and Angular.
All interactions with Windows happen via NodeJs native modules.
There are two native modules for Linux and Windows. In production, one will be used. One module is to work with Windows (position, style, size). The second module is to intercept the mouse pointer and hotkeys. We use this functionality to shot Videos.
There are three native modules for macOS. Two bring core functionality and the third one is to get particular information about the application.
The challenging part here is to build and achieve similar behavior on all OS.
At the end of the week, SMBAct got a pipeline for the application in Jenkins as well.
As usual, software development causes a lot of 🐞 and fixes for them.
At the end of the week, I implemented the save/restore of Settings functionality.
Screenshots are below:
Week 5. Signature and Legalisation time. Unexpected problems.
This week should have been the week of the Application Signature and draft releases of the application. However, it did not turn out.
The approval of the Apple developer took three days. The application for Comodo Individual Signing Certificate took three days as well. The process is non-transparent. The Comodo UI comes from 200x and hasn’t been changed for years.
Microsoft asks a certificate provider to provide all legal information about the developer. As a result, the process is similar to the application for a bank account. You have to provide official and unofficial documents from the government and conduct the face-to-face verification process.
Hopefully, I got all certificates and was ready to sign. The Apple statement regarding the signature is:
Gatekeeper on macOS helps protect users from downloading and installing malicious software by checking for a Developer ID certificate from apps distributed outside the Mac App Store. Make sure to sign any apps, plug-ins, or installer packages that you distribute to let Gatekeeper know they’re safe to install.
I had prepared an unsigned draft release of the SMBAct application for macOS without signature and performed all necessary steps in macOS Ventura to allow the application to run without signature. And here hell began 👿 🔥.
The macOS x64 build started working smoothly as expected without any issues. The Silicon macOS build lost the Accessibility permissions in the subprocess responsible for Windows management. I tried to do several workarounds and tried to move logic to a different process without luck. I went to the Electron community in Discord and Reddit without any success. I googled a lot without luck. I asked ChatGPT and got nothing. The final point was to create the issue in the ElectronJS GitHub.
There are five cents from my side about ElectronJS Github:
I have a strong feeling that people who understand inter-process communication, permissions, and specific things in a certain operating system don’t look at GitHub.
They tend to solve problems such as the Window title does not work or the close button vanished.
Problems that require a very deep understanding of OS have remained unsolved for years.
As a result, they closed my issue with a silly comment. I was pissed off.
I decided to implement a simple Electron JS application without all stuff around. The main purpose was to have a fast and easy-to-build app that reproduces the issue. It was the best decision I made.
I realized that if I run the application from the signed application such as a terminal or a development application my subprocess has all the required permissions.
I signed my test application and it started working 🥰😍🤩🥳 on the Apple Silicon Mac.
There was a small task that I implemented in the fifth week. I was exhausted that my six-year-old son switched off a PC with headless macOS. After the restart, I had to devote some time to make it live and run again. As a result, I made it properly via Ansible and restarted services in Docker.
Week 6. Bugs. AWS s3. Death of Ubuntu. Apple Notarization. Final steps in pipelines. Covid.
The week started with fixing a lot of annoying bugs in the application. I created a new issue on ElectronJS GitHub. The application crashed after some actions. Unfortunately, again it was closed by the Electron team because the investigation of crashes is a very complicated process.
Next, I taught my Ansible working with AWS s3 and started storing all build artifacts in the Amazon storage.
I reorganized pipelines to perform the step of building shared bundles(in terms of Electron they are called Main and Renderer) once and distributing them via the artifactory to a dedicated Jenkins agent. I get used to working with Nexus as the artifactory.
Here I came to the time of the Apple Notarization. I wrote already that I use a headless macOS for Apple builds. However, I prepared the image without XCode installed. The XCode is mandatory for the notarization step. Luckily I was able to find a solution on how to install XCode via terminal. The guy who wrote the command line tool for XCode did a great job.
Unfortunately, my developer Ubuntu died. I had to reinstall it from scratch. This is the reason why SMBAct has not had a Linux distribution yet. This is how I tried to create a Linux install USB stick on Mac. I can confirm without success 👇:
The notarization step was added to the macOS pipeline. Tested on the small application and passed successfully for my small Electron application from the first attempt.
You cannot afford to test against Apple’s notarization servers. Apple allows you to do 70 notarizations per day on a basic developer plan. Every attempt costs two (Arm and Intel).
At the end of the week, Covid hit me heavily. I remember only for two days I tried to work at least 15-30 minutes. My Gold rule is “Work at least 15 minutes per day on your side project.”
Final Week and Day 50.
Bugs, bugs, and a lot of bugs. Stabilization of pipelines and finally installation packages of SMBAct for Windows and macOS were ready.
I started working on the second part of the license server this week as well. I hope it will be a new post in the second part of my journey.
Despite the awful community and GitHub support Electron is the best cross-platform solution. I was working with Qt, and wxWidgets before.
Never underestimate build and deployment time.
Automate everything at the beginning. It will save a tremendous amount of time.
A reasonable question is: Am I alone? No, I am not alone. My wife does all the front-end things and does marketing for our products.
I am a technical founder who develops boring and technically complex products
On my Twitter @bodryachog, I write on a daily basis what I am doing.
The SMBAct application page is here.