Convert the whole site to use Pelican instead of Jekyll

This commit is contained in:
2019-11-05 06:21:56 +01:00
parent 49961a3007
commit d5c1c942f0
534 changed files with 7315 additions and 6642 deletions

View File

@@ -0,0 +1,12 @@
cut-at-ten
##########
:status: draft
:author: Gergely Polonkai
:date: 2019-11-03T07:21Z
.. code-block:: lisp
(defun cut-at-ten ()
(while (re-search-forward "," (save-excursion (end-of-line) (point)) t 10)
(newline-and-indent)))

View File

@@ -0,0 +1,15 @@
GtkActionable in action
#######################
:status: draft
:author: "Gergely Polonkai"
:date: 2017-09-17T00:00Z
I have seen several people (including myself) struggling with disabling/enabling menu items,
toolbar buttons and similar UI interfaces based on different conditions. It gets even worse if
there are multiple representations of the same action in the same application, e.g. a menu item
and a toolbar button exists for the same action. But with GTK+ 3.4, we have GtkAction, which is
exactly for this kind of situations.
.. include:: ../files/gtk-actionable-test.glade
:code: xml

View File

@@ -0,0 +1,14 @@
Measuring code coverage with codecov for libtool projects
#########################################################
:author: Gergely Polonkai
:status: draft
:date: 2017-09-17T02:00Z
I have recently found `codecov <https://codecov.io/>`_; they offer free services for public GitHub
projects. As I have recently started writing tests for my SWE-GLib project, I decided to give it
a go. Things are not this easy if you use GNU Autotools and libtool, though…
The problem here is that these tools generate output under ``src/.libs/`` (given that your sources
are under ``src/``) and ``gcov`` has hard times finding the coverage data files. Well, at least
in the codecov environment, it works fine on my machine.

View File

@@ -0,0 +1,55 @@
Programming, as I see it
########################
:category: blog
:status: draft
:author: Gergely Polonkai
:date: 2017-09-17T02:00Z
since my age of around 11, i write code. i began with basic, which is, well, the most basic
language i have ever seen. simply writing ``10 print "hello world!"`` does the job (with assembly
it would be tens of lines as i recall). then i moved to pascal, then delphi (which is basically
the same thing). the next step was a bit longer, as i started learning more languages after this,
like perl (for dynamic web pages), c (for desktop applications), tcl (for eggdrop programming.
yes, i might have been a weird kid), php (again, for dynamic web pages. it was becoming
mainstream back then).
many of my classmates looked down on me, as they thought i was a geek (hell i was, but i wouldnt
have confessed it then), and called me a nerd. for a few months maybe i was depressed, but after
that i realised that this is the thing i want to do in my life, this is the thing im good at.
Most people I ask why dont they code say “its too hard”. Ive attended some courses (both
online and offline, and I was like “Whoa! Coding is extremely hard! What the hell! I will never
learn it!”, but right after the course I realised that everything is just fine, I can still write
programs, and its eeeeasy. So then, whats the problem?
After looking through many course papers, I found that most teachers do it totally wrong. A
programming language is just that: a language. You dont start learning Spanish by going into a
classic literature conference in Madrid and doing a speech, but learn the basic vocabulary and
grammar. The same goes for coding. You learn the vocabulary (the basic commands or keywords) and
grammar (syntax). I had several ideas how this could be taught, just didnt have the background
to do it.
The idea of teaching programming lingers in my head for years now, and a few days ago, Ive bumped
into `this video <https://www.youtube.com/watch?v=dU1xS07N-FA>`_. So it seems that technology
superstars like Bill Gates and Mark Zuckerberg wants to do the same. Maybe they dont have enough
high quality coders at hand. Well of course, if teachers make it awfully hard to learn it! So a
bunch of guys sat together and created `code.org <http://www.code.org/>`_ to achieve my old dream.
I like the idea. And although I have almost no visitor on this blog of mine, allow me to give you
a few points on how I see programming.
Great learning process
======================
When you write programs, especially during the first years, you adapt a new way of thinking and
learning. If you learn it as an adult, it can be a bit of a pain, but as a child, its easy as
learning how the wheels of those little cars spin).
A job
=====
Art
===
Magic
=====

View File

@@ -0,0 +1,315 @@
Writing a GNOME Shell extension
###############################
:date: 2017-09-17T03:00Z
I could not find a good tutorial on how to write a GNOME Shell extension. There is a so called
step by step `instruction list
<https://wiki.gnome.org/Projects/GnomeShell/Extensions/StepByStepTutorial>`_ on how to do it, but
it has its flaws, including grammar and clearance. As I wanted to create an extension for my SWE
GLib library to display the current position of some planets, I dug into existing (and working)
extensions source code and made up something. Comments welcome!
---
GNOME Shell extensions are written in JavaScript and are interpreted by `GJS
<https://wiki.gnome.org/action/show/Projects/Gjs>`_. Using introspected libraries from JavaScript
is not a problem for me (see SWE GLibs `Javascript example
<https://github.com/gergelypolonkai/swe-glib/blob/master/examples/basic.js>`_; its not beautiful,
but its working), but wrapping your head around the Shells concept can take some time.
The Shell is a Clutter stage, and all the buttons (including the top-right “Activities” button)
are actors on this stage. You can add practically anything to the Shell panel that you can add to
a Clutter stage.
The other thing to remember is the lifecycle of a Shell extension. After calling ``init()``, there
are two ways forward: you either use a so called extension controller, or plain old JavaScript
functions ``enable()`` and ``disable()``; I will go on with the former method for reasons
discussed later.
If you are fine with the ``enable()``/``disable()`` function version, you can ease your job with
the following command:
.. code-block:: shell
gnome-shell-extension-tool --create-extension
This will ask you a few parameters and create the necessary files for you. On what these
parameters should look like, please come with me to the next section.
Placement and naming
====================
Extensions reside under ``$HOME/.local/share/gnome-shell/extensions``, where each of them have its
own directory. The directory name has to be unique, of course; to achieve this, they are usually
the same as the UUID of the extension.
The UUID is a string of alphanumeric characters, with some extras added. Generally, it should
match this regular expression: ``^[-a-zA-Z0-9@._]+$``. The convention is to use the form
``extension-name@author-id``, e.g. ``Planets@gergely.polonkai.eu``. Please see `this link
<https://wiki.gnome.org/Projects/GnomeShell/Extensions/UUIDGuidelines>`_ for some more information
about this.
Anatomy of an extension
=======================
Extensions consist of two main parts, ``metadata.json`` and ``extension.js``.
The ``metadata.json`` file contains compatibility information and, well, some meta data:
.. code-block:: json
{
"shell-version": ["3.18"],
"uuid": "planets@gergely.polonkai.eu",
"name": "Planets",
"description": "Display current planet positions"
}
Here, ``shell-version`` must contain all versions of GNOME Shell that is known to load and display
your extension correctly. You can insert minor versions here, like I did, or exact version
numbers, like ``3.18.1``.
In the ``extension.js`` file, which contains the actual extension code, the only thing you
actually need is an ``init()`` function:
.. code-block:: javascript
function init(extensionMeta) {
// Do whatever it takes to initialize your extension, like initializing the translations.
// However, never do any widget magic here yet.
// Then return the controller object
return new ExtensionController(extensionMeta);
}
Extension controller
====================
So far so good, but what is this extension controller thing? It is an object which is capable of
managing your GNOME Shell extension. Whenever the extension is loaded, its ``enable()`` method is
called; when the extension is unloaded, you guessed it, the ``disable()`` method gets called.
.. code-block:: javascript
function ExtensionController(extensionMeta) {
return {
extensionMeta: extensionMeta,
extension: null,
enable: function() {
this.extension = new PlanetsExtension(this.extensionMeta);
Main.panel.addToStatusArea("planets", this.extension, 0, "right");
},
disable: function() {
this.extension.actor.destroy();
this.extension.destroy();
this.extension = null;
}
}
}
This controller will create a new instance of the ``PlanetsExtension`` class and add it to the
panels right side when loaded. Upon unloading, the extensions actor gets destroyed (which, as
you will see later, gets created behind the scenes, not directly by us), together with the
extension itself. Also, for safety measures, the extension is set to ``null``.
The extension
=============
The extension is a bit more tricky, as, for convenience reasons, it should extend an existing
panel widget type.
.. code-block:: javascript
function PlanetsExtension(extensionMeta) {
this._init(extensionMeta);
}
PlanetsExtension.prototype = {
__proto__ = PanelMenu.Button.prototype,
_init: function(extensionMeta) {
PanelMenu.Button.prototype._init.call(this, 0.0);
this.extensionMeta = extensionMeta;
this.panelContainer = new St.BoxLayout({style_class: 'panel-box'});
this.actor.add_actor(this.panelContainer);
this.actor.add_style_class_name('panel-status-button');
this.panelLabel = new St.Label({
text: 'Loading',
y_align: Clutter.ActorAlign.CENTER
});
this.panelContainer.add(this.panelLabel);
}
};
Here we extend the ``Button`` class of ``panelMenu``, so we will be able to do some action upon
activate.
The only parameter passed to the parents ``_init()`` function is ``menuAlignment``, with the
value ``0.0``, which is used to position the menu arrow. (*Note: I cannot find any documentation
on this, but it seems that with the value ``0.0``, a menu arrow is not added.*)
The extension class in its current form is capable of creating the actual panel button displaying
the text “Loading” in its center.
Loading up the extension
========================
Now with all the necessary import lines added:
.. code-block:: javascript
// The PanelMenu module that contains Button
const PanelMenu = imports.ui.panelMenu;
// The St class that contains lots of UI functions
const St = imports.gi.St;
// Clutter, which is used for displaying everything
const Clutter = imports.gi.Clutter;
As soon as this file is ready, you can restart your Shell (press :kbd:`Alt-F2` and enter the
command ``r``), and load the extension with e.g. the GNOME Tweak Tool. You will see the Planets
button on the right. This little label showing the static text “Planets”, however, is pretty
boring, so lets add some action.
Adding some periodical change
=============================
Since the planets position continuously change, we should update our widget every minute or
so. Lets patch our ``_init()`` a bit:
.. code-block:: javascript
this.last_update = 0;
MainLoop.timeout_add(1, Lang.bind(this, function() {
this.last_update++;
this.panelLabel.set_text("Update_count: " + this.last_update);
}))
This, of course, needs a new import line for ``MainLoop`` to become available:
.. code-block:: javascript
const MainLoop = imports.mainloop;
const Lang = imports.lang;
Now if you restart your Shell, your brand new extension will increase
its counter every second. This, however, presents some problems.
SWE GLib queries can sometimes be expensive, both in CPU and disk operations, so updating our
widget every second may present problems. Also, planets dont go **that** fast. We may update
our timeout value from ``1`` to ``60`` or something, but why dont just give our user a chance to
set it?
Introducing settings
====================
Getting settings from ``GSettings`` is barely straightforward, especially for software installed
in a non-GNOME directory (which includes extensions). To make our lives easier, I copied over a
`convenience library
<https://github.com/projecthamster/shell-extension/blob/master/convenience.js>`_ from the `Hamster
project <https://projecthamster.wordpress.com/>`_s extension, originally written by Giovanni
Campagna. The relevant function here is ``getSettings()``:
.. code-block:: javascript
/**
* getSettings:
* @schema: (optional): the GSettings schema id
*
* Builds and return a GSettings schema for @schema, using schema files
* in extensionsdir/schemas. If @schema is not provided, it is taken from
* metadata['settings-schema'].
*/
function getSettings(schema) {
let extension = ExtensionUtils.getCurrentExtension();
schema = schema || extension.metadata['settings-schema'];
const GioSSS = Gio.SettingsSchemaSource;
// check if this extension was built with "make zip-file", and thus
// has the schema files in a subfolder
// otherwise assume that extension has been installed in the
// same prefix as gnome-shell (and therefore schemas are available
// in the standard folders)
let schemaDir = extension.dir.get_child('schemas');
let schemaSource;
if (schemaDir.query_exists(null))
schemaSource = GioSSS.new_from_directory(schemaDir.get_path(),
GioSSS.get_default(),
false);
else
schemaSource = GioSSS.get_default();
let schemaObj = schemaSource.lookup(schema, true);
if (!schemaObj)
throw new Error('Schema ' + schema + ' could not be found for extension '
+ extension.metadata.uuid + '. Please check your installation.');
return new Gio.Settings({ settings_schema: schemaObj });
}
You can either incorporate this function into your ``extension.js`` file, or just use
``convenience.js`` file like I (and the Hamster applet) did and import it:
.. code-block:: javascript
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension;
const Convenience = Me.imports.convenience;
Now lets create the settings definition. GSettings schema files are XML files. We want to add
only one settings for now, the refresh interval.
.. code-block:: xml
<?xml version="1.0" encoding="utf-8"?>
<schemalist>
<schema id="org.gnome.shell.extensions.planets" path="/org/gnome/shell/extensions/planets/">
<key name="refresh-interval" type="i">
<default>30</default>
<summary>Refresh interval of planet data</summary>
<description>Interval in seconds. Sets how often the planet positions are recalculated. Setting this too low (e.g. below 30) may raise performance issues.</description>
</key>
</schema>
</schemalist>
you need to compile these settings with
.. code-block:: shell
glib-compile-schemas --strict schemas/
Now lets utilize this new setting. In the extensions ``_init()`` function, add the following
line:
.. code-block:: javascript
this._settings = Convenience.getSettings();
And, for ``getSettings()`` to work correctly, we also need to extend our ``metadata.json`` file:
.. code-block:: json
"settings-schema": "planets"
After another restart (please, GNOME guys, add an option to reload extensions!), your brand new
widget will refresh every 30 seconds.
Displaying the planet positions
===============================
The settings panel
==================
Start an application
====================

View File

@@ -0,0 +1,54 @@
Lessons you learn while writing an SDK
######################################
:tags: development
:author: Gergely Polonkai
:date: 2017-09-17T01:00Z
In the last few months Ive been working on a GLib based SDK for client applications that want to
communicate with a Matrix.org homeserver.
For whoever doesnt know it, Matrix is a decentralized network of servers (Homeservers). Clients
can connect to them via HTTP and send messages (events, in Matrix terminology) to each other.
They are called events because these messages can be pretty much anything from instant messages
through automated notifications to files or, well, actual events (such as a vCalendar); anything
that you can serialize to JSON can go through this network.
My original intention was to integrate Matrix based chat into Telepathy, a DBus based messaging
framework used by e.g. the GNOME desktop (more specifically Empathy, GNOME's chat client.) After
announcing my plans among the Matrix devs, I quickly learned some things:
1. they are more than open to any development ideas
2. they really wanted to see this working
3. they would have been happy if there were a GLib or Qt based SDK
With my (far from complete) knowledge in GLib I decided to move on with this last point, hoping
that it will help me much when I finally implement the Telepathy plugin.
Matrix devs are open minded
===========================
What I learned very quickly is that Matrix devs are very open minded folks from different parts of
the world. They are all individuals with their own ideas, experiences and quirks, yet, when it
comes to that, they steer towards their goals as a community. Thus, getting additional
information from them while reading the spec was super easy.
The specification is easy to understand
=======================================
Except when it is not. For these cases, see the previous point.
Jokes aside, anyone who worked with communications protocols or JSON APIs before can get along
with it fast. The endpoints are all documented, and if something is unclear, they are happy to
help (especially if you patch up the spec afterwards.)
Copying the SDK for a different language is not (always) what you want
======================================================================
I started my SDK in C, trying to mimic the Python SDK. This was a double fail: the Python SDK was
a volatile WiP, and C and Python are fundamentally different.
During the upcoming weeks this became clear and I switched to the Vala language. It is much
easier to write GObject based stuff in Vala, although I had to fall back to C to get some features
working. I also planned and implemented a more object oriented API, which is easier to use in the
GObject world.