ia: Benvenite! In mi blog io scribe in interlingua, italiano e anglese.

it: Benvenuti! Nel mio blog scrivo in interlingua, italiano e inglese.

en: Welcome! In my blog I write in Interlingua, Italian and English.

Implementing "Open with…" on MacOS with Qt

I just released PhotoTeleport 0.12, which includes the feature mentioned in the title of this blog post. Given that it took me some time to understand how this could work with Qt, I think it might be worth spending a couple of lines about how to implement it.

In the target application

The first step (and the easiest one) is about adding the proper information to your .plist file: this is needed to tell MacOS what file types are supported by your application. The official documentation is here, but given that an example is better than a thousand words, here's what I had to add to PhotoTeleport.plist in order to have it registered as a handler for TIFF files:

  <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeExtensions</key>
      <array>
        <string>tiff</string>
        <string>TIFF</string>
        <string>tif</string>
        <string>TIF</string>
      </array>
      <key>CFBundleTypeMIMETypes</key>
      <array>
        <string>image/tiff</string>
      </array>
      <key>CFBundleTypeName</key>
      <string>NSTIFFPboardType</string>
      <key>CFBundleTypeOSTypes</key>
      <array>
        <string>TIFF</string>
        <string>****</string>
      </array>
      <key>CFBundleTypeRole</key>
      <string>Viewer</string>
      <key>LSHandlerRank</key>
      <string>Default</string>
      <key>LSItemContentTypes</key>
      <array>
        <string>public.tiff</string>
      </array>
      <key>NSDocumentClass</key>
      <string>PVDocument</string>
    </dict>
    …more dict entries for other supported file formats…
  </array>

This is enough to have your application appear in Finder's "Open with…" menu and be started when the user selects it from the context menu, but it's only half of the story: to my big surprise, the selected files are not passed to your application as command line parameters, but via some MacOS-specific event which needs to be handled.

By grepping into the Qt source code, I've found out that Qt already handles the event, which is then transformed into a QFileOpenEvent. The documentation here is quite helpful, so I won't waste your time to repeat it here; what has hard for me was to actually find that this functionality exists and is supported by Qt.

In the source application

The above is only half of the story: what if you are writing an application which wants to send some files to some other application? Because of the sandboxing, you cannot just start the desired application in a QProcess and pass the files as parameters: again, we need to use the Apple Launch Services so that the target application would receive the files through the mechanism described above.

Unfortunately, as far as I could find this is not something that Qt supports; sure, with QDesktopServices::openUrlExternally() you can start the default handler for the given url, but what if you need to open more than one file at once? And what if you want to open the files in a specific application, and not just in the default one? Well, you need to get your hands dirty and use some MacOS APIs:

#import <CoreFoundation/CoreFoundation.h>
#import <ApplicationServices/ApplicationServices.h>

void MacOS::runApp(const QString &app, const QList<QUrl> &files)
{
    CFURLRef appUrl = QUrl::fromLocalFile(app).toCFURL();

    CFMutableArrayRef cfaFiles =
        CFArrayCreateMutable(kCFAllocatorDefault,
                             files.count(),
                             &kCFTypeArrayCallBacks);
    for (const QUrl &url: files) {
        CFURLRef u = url.toCFURL();
        CFArrayAppendValue(cfaFiles, u);
        CFRelease(u);
    }

    LSLaunchURLSpec inspec;
    inspec.appURL = appUrl;
    inspec.itemURLs = cfaFiles;
    inspec.asyncRefCon = NULL;
    inspec.launchFlags = kLSLaunchDefaults + kLSLaunchAndDisplayErrors;
    inspec.passThruParams = NULL;

    OSStatus ret;
    ret = LSOpenFromURLSpec(&inspec, NULL);
    CFRelease(appUrl);
}

In Imaginario I've saved this into a macos.mm file, added it to the source files, and also added the native MacOS libraries to the build (qmake):

LIBS += -framework CoreServices

You can see the commit implementing all this, it really doesn't get more complex than this. The first parameter to the MacOS::runApp() function is the name of the application; I've verified that the form /Applications/YourAppName.app works, but it may be that more human-friendly variants work as well.

Bussator: implementing webmentions as comments

Recently I've grown an interest to the indieweb: as big corporations are trying to dictate the way we live our digital life, I'm feeling the need to take a break from at least some of them and getting somehow more control over the technologies I use.

Some projects have been born which are very helpful with that (one above all: NextCloud), but there are also many older technologies which enable us to live the internet as a free distributed network with no owners: I'm referring here to protocols such as HTTP, IMAP, RSS, which I perceive to be under threat of being pushed aside in favor of newer, more convenient, but also more oppressive solutions.

Anyway. The indieweb community is promoting the empowerment of users, by teaching them how to regain control of their online presence: this pivots arund having one's own domain and use self-hosted or federated solutions as much as possible.

One of the lesser known technologies (yet widely used in the indieweb community) is webmentions: in simple terms, it's a way to reply to other people's blog posts by writing a reply in your own blog, and have it shown also on the original article you are replying to. The protocol behind this feature is an recommendation approved by the W3C, and it's actually one of the simplest protocol to implement. So, why not give it a try?

I already added support for comments in my blog (statically generated with Nikola) by deploying Isso, a self-hosted commenting system which can even run as a FastCGI application (hence, it can be deployed in a shared hosting with no support for long-running processes) — so I was looking for a solution to somehow convert webmentions into comments, in order hot to have to deal with two different commenting systems.

As expected, there was no ready solution for this; so I sat down and hacked up Bussator, a WSGI application which implements a webmention receiver and publishes the reply posts as Isso comments. The project is extensible, and Isso is only one of the possible commenting systems; sure, at the moment it's indeed the only one available, but there's no reason why a plugin for Static Man, Commento, Remark or others couldn't be written. I'll happily accept merge requests, don't be shy — or I can write it myself, if you convince me to (a nice Lego box would make me do anything 😉).

The first user of Bussator is this blog, and while the project code is well covered by unit tests, we all know that real life is all another matter; so please bear with me, if not everything works as it should. And that's why I'll be thrilled to see your webmentions replies here.

Ah, and webmentions will allow me to get your Twitter likes and replies published as comments, too — this thanks to Brid.gy!

On Richard Stallman and people who cannot read

We live in strange times. People are so filled with hatred and prejudices that their brain becomes unable to parse the simplest sentences. I take this issue to heart, because it could happen to anyone — it has happened to me before (luckily, only in private online conversations), where an acquaintance of mine accused me of saying things I never said. And it happens to famous people all the time. Guys, just because you hate person X, you should not skip over parts of their speech or suppress context in order to make it look like they said something terrible or stupid, when they didn't.

Now it happend to Richard Stallman, with a whole wave of hateful people accusing him of saying something that he didn't say. Let's start with the VICE article, titled "Famed Computer Scientist Richard Stallman Described Epstein Victims As 'Entirely Willing'", which insists in quoting only two words out of Stallman's sentence:

Early in the thread, Stallman insists that the “most plausible scenario” is that Epstein’s underage victims were “entirely willing” while being trafficked.

Except that he didn't say that. Why not quote the whole sentence? It's not such a long sentence, really! Just follow the link to the source, which provides a complete excerpt of Stallman's words:

We can imagine many scenarios, but the most plausible scenario is that she presented herself to him as entirely willing. Assuming she was being coerced by Epstein, he would have had every reason to tell her to conceal that from most of his associates.

Now, English is not my native language, but I read it well enough to understand that “to present oneself as” and “to be” are different expressions having very different meanings (and, in most context, actually opposite ones!). You don't need to be Shakespeare to understand that. You only need to either stop hating or, if you really cannot help it, at least stop projecting your prejudices onto the people you hate. Hate makes you blind.

It's sad to see otherwise intelligent people take stupid decisions because of such misunderstandings.

I for one, stand in solidarity with Richard Stallman and with the English language.

(please note that this is not an endorsement of everything Stallman might have said in the past; I don't follow him that closely, and it may be that he also happened to say terrible things in this very thread. I'm only commenting this very specific issue, and I know that in this very specific issue he's being wrongly accused)

Principles and privileges

I intended to write a reply to Jos Poortvliet's blog post “Principles”, and I swear I did enter it as a comment to his Google-powered blog, but something went wrong and when I tried to publish it I lost all what I'd written. So I decided to let some hours pass, ponder a bit more over the subject, and write a more exhaustive answer on my own blog.

“A morte il fascio” — death to fascism.

Before going into the core of the topic, I want to point out that when I start thinking over the questions posed by Jos my thought can't help jumping to the Marxist concept of classes: the very fact that you are considering the possibility of refusing a business because of principles means that you can afford doing that, while most people just can't. The same applies to similar questions, such as declining a well paying job because of ethical reasons, or boycotting some products, eating healthy food, crossing the ocean on a clean yacht instead of polluting the air by plane, etc.: being able to make these choices already imply that you are in a privileged position (in some cases, extremely privileged!).

Why am I saying that? Certainly not to diminish the value of your ethical choices! By all means, please continue to do your best to change things! However, while you can proudly look at yourself in the mirror, please don't look down on people who don't seem to be as responsible as you: they might simply not have the choice, or not be able to afford it. Or maybe — that's also possible — they are not aware that they can make this choice.

So, besides being excellent yourself, one thing you could do in order to have a much bigger impact is to help other people get into a condition such that they would also be able to afford to take the brave choices you go proud of.

That was a long premise indeed, but it might help to understand the rest of my answer.

Which is: yes, I would (to a question like “Would you work with a company that builds rockets and bombs to earn money for Nextcloud development?”). Which might surprise many, especially those of you who know that I'm a hardcore pacifist. In reality, my answer would be much more faceted, depending on who you are and on the weight of your possible refusal. For example, if I were a superstar with a million followers, then I'd definitely refuse: such a decision, made public, would have a strong propagandistic effect. But when you are an ordinary software developer, with a dozen friends (or even a few hundreds) and no direct channel to the media, what would be the outcome of your refusal? It might impress a handful of people, maybe, but the evil company would easily find someone else to replace you and you'd lose a well paying job (which could help you to afford making more ethical choices). But more important than that, you would have cut out a communication channel to the people who might benefit the most from your presence — and from your message.

I would answer “yes” because I'd like to take a chance to know what people on the other side of the fence think. What are their reasons? Are they aware of the issues that bother me? It's possible that I'm overestimating myself, but even if there was a tiny, microscopic chance of instilling a doubt, of delivering a message or providing a good example, I would leave no stone unturned to grasp this chance. Of course, I'm not thinking of “converting” the management of a corporation; but some of my peers inside that company might start questioning things. And then, of course, you can always leave, when enough is enough; but joining and then leaving a deal has a higher impact than no joining at all. Or, if you like metaphores, in order to clean something, you first have to get your hands dirty.

Before reading Jos's post, I've been considering another question, which is vaguely related. Suppose that you were the owner of a bakery, and that you knew that one of your customer is a nazi. Would you still sell bread to him? Suppose that he's the only nazi in town: here you don't even need to worry about your business, because even if you lost that customer, it wouldn't have but a very minor impact on you.

My answer here is along a similar line as the previous one: yes, I would still sell my bread to him. One reason is that this risks being another rabbit hole: a nazi might hold the most disgusting opinions and views, but then — if you think about it — many people do. Maybe they don't hate Jews, but Roms, Muslims, lawyers, or the French; maybe they don't want to colonize Africa, but Greece; maybe they don't physically torture dissidents, but keep them rotting in a jail without charges (or with made-up charges). Even without going to these extremes, there's simply the fact that we are all imperfect: both in our opinions and in our actions. Would you refuse selling bread to a guy holding nazi views, but otherwise honest and well-behaving, while selling it to someone having well-balances opinions, but who evades millions in taxes?

But the main reason why I'd sell my bread to a nazi is that, really, I'd like to get to know him. I would like to learn why he holds those views, because I think that understanding is the first step towards correction. This is probably matter for a future post, but I'm convinced that all this censorship in the social networks (yes, especially on the federated ones!) is detrimental to the fight against fascism: if we won't even know where and who the fascists are, how can we have any hopes of winning the fight?

So, let's build bridges, let's talk, let's try to understand each other's points of view, and find exactly why we see things differently. And this is much more effective when done at a personal level, one to one, rather than with public big proclaims — which, more often than not, have the only effect of polarizing the field even more.

In short — and I guess this is my answer to Jos — try to make a difference with those who are closer to you. Accept the deal with the evil corporation, and let everyone of your friends and colleagues know how much you are suffering because of that. Let your peers in that company know you for what you are worth, but don't hide your feelings. Maybe, who knows, the day you leave the deal, they will also decide that it's time to make a big choice in their life?

Migrating to a new Mastodon instance

The wonders of improvised Mastodon instances: one node disappears after an outage caused by a summer heatwave, leaving its users no way to migrate their data or to notify their followers.

After about one month of waiting for the node to come up or give some signals of life, I've decided to create a new account on another instance. If you use Mastodon and you were following me, please forgive me for the annoyance and follow me again here.