Convert the whole site to use Pelican instead of Jekyll
This commit is contained in:
12
content/drafts/cut-at-ten.rst
Normal file
12
content/drafts/cut-at-ten.rst
Normal 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)))
|
15
content/drafts/gtk-actionable-in-action.rst
Normal file
15
content/drafts/gtk-actionable-in-action.rst
Normal 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
|
@@ -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.
|
55
content/drafts/programming-as-i-see-it.rst
Normal file
55
content/drafts/programming-as-i-see-it.rst
Normal 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 wouldn’t
|
||||
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 i’m good at.
|
||||
|
||||
Most people I ask why don’t they code say “it’s too hard”. I’ve 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 it’s eeeeasy. So then, what’s 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 don’t 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 didn’t have the background
|
||||
to do it.
|
||||
|
||||
The idea of teaching programming lingers in my head for years now, and a few days ago, I’ve 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 don’t 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, it’s easy as
|
||||
learning how the wheels of those little cars spin).
|
||||
|
||||
A job
|
||||
=====
|
||||
|
||||
Art
|
||||
===
|
||||
|
||||
Magic
|
||||
=====
|
315
content/drafts/writing-a-gnome-shell-extension.rst
Normal file
315
content/drafts/writing-a-gnome-shell-extension.rst
Normal 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 GLib’s `Javascript example
|
||||
<https://github.com/gergelypolonkai/swe-glib/blob/master/examples/basic.js>`_; it’s not beautiful,
|
||||
but it’s working), but wrapping your head around the Shell’s 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
|
||||
panel’s right side when loaded. Upon unloading, the extension’s 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 parent’s ``_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 let’s add some action.
|
||||
|
||||
Adding some periodical change
|
||||
=============================
|
||||
|
||||
Since the planets’ position continuously change, we should update our widget every minute or
|
||||
so. Let’s 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 don’t go **that** fast. We may update
|
||||
our timeout value from ``1`` to ``60`` or something, but why don’t 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 let’s 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 let’s utilize this new setting. In the extension’s ``_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
|
||||
====================
|
54
content/drafts/writing-an-sdk.rst
Normal file
54
content/drafts/writing-an-sdk.rst
Normal 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 I’ve been working on a GLib based SDK for client applications that want to
|
||||
communicate with a Matrix.org homeserver.
|
||||
|
||||
For whoever doesn’t 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.
|
Reference in New Issue
Block a user