Skip to content

Custom Modules

Federico edited this page Aug 29, 2019 · 18 revisions

Custom modules

Starting with Clight 4.0, thanks to libmodule 5.0.0 port, clight is capable of runtime loading custom modules.
This means users can write their own specific modules to customize Clight behaviour.

Clight will load modules located in:

  • System-wide: $CMAKE_INSTALL_FULL_DATADIR/clight/modules.d/ (normally /usr/share/clight/modules.d)
  • User: $XDG_DATA_HOME/clight/modules.d/ (defaults to $HOME/.local/share/clight/modules.d/)

Note that User modules take precedence.
There can only be a single module with same name in Clight; thus the following rules apply:

  • Nobody can override a clight internal module
  • An User custom module can override a System custom module (by taking same name)

Clight takes advantage of libmodule's PubSub interface that makes it super easy to interact with Clight private modules.
The idea here is that custom modules should subscribe to certain Clight internal events, and react to them by publishing requests to Clight internal modules.

Custom modules behave just like private Clight modules but:

  • have no access to Clight conf
  • have no access to Clight internal state
  • can log to clight's log just like any other module, but cannot use ERROR() log macro (that would exit clight)

In the end, they can only interact with other modules through PubSub interface as defined in clight/public.h header.

Clight public API

Clight will install its public API in ${CMAKE_INSTALL_INCLUDEDIR}/clight/public.h (normally /usr/include/clight/public.h).
Note that, while I'll strongly try to avoid any API break, this API should be considered as unstable, and may change in the future.

Examples

A couple of skeletons modules are provided too, to be either customized or used right away. You can find them in $CMAKE_INSTALL_FULL_DATADIR/clight/*.skel.

I will list them here; they implement a couple of highly requested behaviours.
The first, very simple custom module, adds support for changing your DE theme on daytime updates (eg: dark theme on NIGHT and normal theme during the DAY).
It is pretty straightforward:

#include <clight/public.h>

CLIGHT_MODULE("DAYTIME");

static void init(void) {
    /* Suscribe to daytime updates */
    M_SUB(TIME_UPD);
}

static void receive(const msg_t *msg, const void *userdata) {
    switch (MSG_TYPE()) {
    case TIME_UPD: {
        time_upd *up = (time_upd *)MSG_DATA();
        if (up->new == DAY) {
            // system("lookandfeeltool -a org.kde.breeze.desktop");
            INFO("We're now during the day!\n");
        } else {
            // system("lookandfeeltool -a org.kde.breezedark.desktop");
            INFO("We're now during the night!\n");
        }
        break;
    }
    default:
        break;
    }
}

As you can see, some macros where intentionally developed to make is as simple as possible to develop custom modules.

The second skeleton provide another highly requested feature: setting a certain backlight level and pause backlight autocalibration when Clight gets inhibited (eg: when starting to watch a movie):

#include <clight/public.h>

CLIGHT_MODULE("INHIBIT_BL");

DECLARE_MSG(bl_req, BL_REQ);
DECLARE_MSG(capture_req, CAPTURE_REQ);
DECLARE_MSG(calib_req, NO_AUTOCALIB_REQ);

static void init(void) {
    capture_req.capture.reset_timer = false; // avoid resetting clight internal BACKLIGHT timer
    bl_req.bl.new = 1.0;    // 100% screen backlight
    bl_req.bl.smooth = -1;  // use conf values
    
    /* Subscribe to inhibit state */
    M_SUB(INHIBIT_UPD);
}

static void receive(const msg_t *msg, const void *userdata) {
    switch (MSG_TYPE()) {
    case INHIBIT_UPD: {
        inhibit_upd *up = (inhibit_upd *)MSG_DATA();
        if (up->new) {
            calib_req.nocalib.new = true;
            M_PUB(&calib_req);
            M_PUB(&bl_req);
            INFO("We are now inhibited! Set 100%% screen backlight.\n");
        } else {
            INFO("We're not inhibited anymore. Do a quick backlight calibration.\n");
            calib_req.nocalib.new = false;
            M_PUB(&calib_req);
            M_PUB(&capture_req);
        }
        break;
    }
    default:
        break;
    }
}

This is somewhat more complex and offers a nice overview of all the available possibilities:

  • When you wish to publish a request to Clight private modules, you must DECLARE_MSG() with your desired message type.
  • Requests can have mandatory fields. You can check them out in public header.
  • To publish a message, you should M_PUB() your desired message's address.

All in all, I think this is a really great way to customize your Clight experience!
For any doubt, do not hesitate to contact me.
If you wrote a fresh new custom module, and you wish to share it with other, feel free to open a feature request and propose it to be installed as a skeleton :)

Clone this wiki locally