aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/posts/custom-plugins-dev/index.md
blob: c5ff2b9a2c4cc6cbdcb359500e62fa06f7a83995 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
+++
authors = ["Arun Mani J"]
title = "Build Your Own Quick-Setting or Lock-Screen Widget"
date = "2024-04-10T08:39:22+02:00"
tags = [ "development", "lock-screen", "phosh", "plugins", "quick-settings" ]
images = ["posts/custom-plugins-dev/custom-plugins.png"]
+++

{{< image name="custom-plugins.png" title="Custom plugins in Phosh" >}}

Phosh has support for plugins which can be used to customize and extend certain
aspects as per your liking without touching the internal source code.

Currently Phosh supports plugins for lock-screen and quick-settings. Lock-screen
plugins appear when your phone is in locked state. Plugins here can be used to
show information that doesn't need one to unlock the screen. Examples include
emergency information, upcoming events etc.

Quick-setting plugins are found in the quick-settings box (the one where Wi-Fi,
Bluetooth etc. can be toggled) when you drag the top-panel. Plugins here can be
used to toggle an action like activate caffeine mode.

Read on to learn how to create a plugin and use it.

## Plugins, Extensions - What is What?

People usually confuse between these two words. For our usecase, an extension is
a user interface element that extends the functionality of something. A plugin
is a collection of extensions, like a package.

As an example, suppose we have a plugin to monitor heart-beats, then it can
provide two extensions - a quick-setting to enable and disable the tracker and a
lock-screen extension to show the analytics collected so far.

## Prerequisites

Phosh plugins are usually written in C[^1] and are similar to typical
[Gtk](https://gtk.org) widgets. It means you should be familiar with C, Gtk and
[GLib](https://docs.gtk.org/glib/) based libraries.

You can read our [Development Guide - Getting
Started](https://gitlab.gnome.org/World/Phosh/phosh/-/wikis/Development-Guide#getting-started)
for more information. Especially the [Running
Phosh](https://gitlab.gnome.org/World/Phosh/phosh/-/wikis/Development-Guide#running-phosh)
section as it is highly useful to test your plugins.

## Getting Started

With the requirements set, let us see how to develop a plugin.

{{< notice note >}}
In this guide we will walk you through how to develop an _in-tree_ plugin. That
is, a plugin that is shipped alongside Phosh. You can also use `phosh-plugin.h`
(can be located via `pkg-config --cflags --libs phosh-plugins`) to develop plugins
without cloning Phosh repository.
{{< /notice >}}

First you should clone the [Phosh](https://gitlab.gnome.org/World/Phosh/phosh)
repository and get it
[running](https://gitlab.gnome.org/World/Phosh/phosh#running).

Phosh comes with a sample quick-setting plugin to give an overview of what your
plugin should contain. Head over to
[`plugins/simple-custom-quick-setting`](https://gitlab.gnome.org/World/Phosh/phosh/-/tree/main/plugins/simple-custom-quick-setting?ref_type=heads)
directory and copy it to a new name under the `plugins/` directory.

{{< notice note >}}
If you want to create a plugin for lock-screen or both, the steps are more or
less the same.
{{< /notice >}}

For example, if you are creating a new quick-setting plugin named `heart-beat-monitor`,
then you should have copied `plugins/simple-custom-quick-setting` to
`plugins/heart-beat-monitor`.

Next, you should rename all occurrences of `simple-custom-quick-setting` (and
variations) with your plugin's name in the files inside `plugins/heart-beat-monitor`.

## Plugin Files

Let's have a short look at what each file in your plugin does.

1. [`meson.build`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/meson.build?ref_type=heads)
   - It is a [Meson](https://mesonbuild.com) build file.
   - If your plugin has an external dependency apart from what Phosh uses, then
     you should set it here.
2. [`simple-custom-quick-setting.desktop.in.in`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/simple-custom-quick-setting.desktop.in.in?ref_type=heads)
   - This file provides the metadata of your plugin.
   - You should replace `Name` and `Comment` keys with your plugin details.
   - The `Types` key describes what extensions the plugin supports. Example
     values are `lock-screen;`, `quick-setting;`, `lock-screen;quick-setting;`.
3. [`qs.ui`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/qs.ui?ref_type=heads)
   - It is a
     [UI](https://docs.gtk.org/gtk3/class.Builder.html#gtkbuilder-ui-definitions-builder-ui)
     file.
   - For a lock-screen extension, it can be any valid Gtk widget.
   - However, quick-settings should stick to the structure and modify only the
     properties available.
4. [`phosh-plugin-simple-custom-quick-setting.gresources.xml`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/phosh-plugin-simple-custom-quick-setting.gresources.xml?ref_type=heads)
   - This file lists the
     [resources](https://docs.gtk.org/gio/struct.Resource.html) used by your
     plugin.
   - One obvious resource is the UI file described above.
   - If your plugin needs other resources like icons, CSS files etc. then it
     should be described here.
5. [`phosh-plugin-simple-custom-quick-setting.c`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/phosh-plugin-simple-custom-quick-setting.c?ref_type=heads)
   - This is the entry file used to describe the plugin to the loading mechanisms.
   - You should include your plugin headers.
   - Change `PHOSH_TYPE_SIMPLE_CUSTOM_QUICK_SETTING` to your plugin's, like `PHOSH_TYPE_HEART_BEAT_MONITOR`.
   - Change the extension point to match what extensions your plugin provides.
6. [`simple-custom-quick-setting.h`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/simple-custom-quick-setting.h?ref_type=heads)
7. [`simple-custom-quick-setting.c`](https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/plugins/simple-custom-quick-setting/simple-custom-quick-setting.c?ref_type=heads)
   - The above two files form the core of your plugin.
   - Just like the UI file, if you are making a lock-screen extension, then it
     can be any Gtk widget.
   - For quick-settings, it should stick to the available properties.

The above description can be confusing or vague. Worry not, have a look at the
source code of other plugins. It should give you an idea of what to replace,
what to modify etc. If you still have doubts, feel free to reach us using
[Matrix](https://im.puri.sm/#/room/#phosh:talk.puri.sm).

If you have followed the above steps, then a quick-settings plugin for heart-beat monitoring
would have its `on_clicked` method like the below code.

```c
static void
on_clicked (PhoshHeartBeatMonitor *self)
{
  gboolean active = phosh_quick_setting_get_active (PHOSH_QUICK_SETTING (self));
  
  if (active) {
    phosh_status_icon_set_icon_name (self->info, "action-unavailable-symbolic");
    phosh_status_icon_set_info (self->info, _("Heart Beat Monitor Inactive"));
    /* Inform the sensor to pause monitoring… */
  } else {
    phosh_status_icon_set_icon_name (self->info, "emblem-favorite-symbolic");
    phosh_status_icon_set_info (self->info, _("Heart Beat Monitor Active"));
    /* Inform the sensor to start monitoring… */
  }
 
  phosh_quick_setting_set_active (PHOSH_QUICK_SETTING (self), !active);
}
```

## Testing
### Standalone Testing

In a standalone testing, you only load the set of extensions. It is useful for a
quick testing if your plugin doesn't need Phosh to be running.

1. Enable tools support.

```bash
$ meson configure _build -Dtools=true
```

2. Compile Phosh and plugins.

```bash
$ meson compile -C _build
```

3. Load the extensions.

```bash
# For lock-screen extensions
$ G_MESSAGES_DEBUG="phosh-plugin-heart-beat-monitor" _build/tools/run_tool _build/tools/widget-box
# For quick-settings extensions
$ G_MESSAGES_DEBUG="phosh-plugin-heart-beat-monitor" _build/tools/run_tool _build/tools/custom-quick-settings
```

Now a window should pop-up where you can test your plugin.

{{< image name="heart-beat-monitor-in-standalone.png" title="Heart Beat Monitor plugin loaded for standalone testing" >}}

`G_MESSAGES_DEBUG=phosh-plugin-heart-beat-monitor` shows you the debug messages
logged by your plugin named `heart-beat-monitor`.

### Testing with Phosh

You should be able to test your plugin _locally_ without having to mess up your
system configuration. In the following, we locally install Phosh, set the
plugins and then run Phosh.

1. Change the [installation
   prefix](https://mesonbuild.com/Builtin-options.html).

```bash
$ meson configure _build -Dprefix="/home/user/phosh/install/"
```

This asks Meson to use `/home/user/phosh/install/` as the directory to install
Phosh. Feel free to replace it with any absolute path you like.

2. Compile and install Phosh and the plugins.

```bash
$ meson compile -C _build
$ meson install -C _build
```

3. Set the plugin as enabled.

```bash
$ GSETTINGS_SCHEMA_DIR=_build/data \
  GSETTINGS_BACKEND=keyfile \
  gsettings set sm.puri.phosh.plugins quick-settings "['heart-beat-monitor']"
```

We ask GSettings to enable the quick-settings plugin named `heart-beat-monitor`.
Actually, we are setting `heart-beat-monitor` as the only enabled
quick-settings. It should simplify the testing by loading only your plugin.

For lock-screen extensions use the `lock-screen` key.

`GSETTINGS_SCHEMA_DIR=_build/data` asks GSettings to load the schema from
`_build/data` directory.

`GSETTINGS_BACKEND=keyfile` saves the value to
`$HOME/.config/glib-2.0/settings/keyfile` instead of messing up system settings.

4. Run Phosh.

```bash
$ G_MESSAGES_DEBUG=phosh-plugin-heart-beat-monitor \
  GSETTINGS_SCHEMA_DIR=_build/data \
  phoc -C /usr/share/phosh/phoc.ini \
       -E "PREFIXDIR/libexec/phosh -U"
```

You might have to replace `phoc -C /usr/share/phosh/phoc.ini` with your local
Phoc executable and configuration.

`G_MESSAGES_DEBUG=phosh-plugin-heart-beat-monitor` shows you the debug messages logged by
your plugin named `heart-beat-monitor`.

Change `PREFIXDIR` to the prefix you set in step 1.

Now Phosh should be launched where you can test your plugin.

{{< image name="heart-beat-monitor-in-phosh.png" title="Heart Beat Monitor plugin loaded in Phosh" >}}

## Preferences

Plugins can have preferences which show up in [Phosh Mobile
Settings](https://gitlab.gnome.org/World/Phosh/phosh-mobile-settings). This has
two benefits. As a plugin developer, you need not worry about making preferences
UI part of any extension (like where to place the settings button, should
preferences be a pop-up or separate application etc.). For a user, they have a
unified, standard portal to browse and configure all their plugins.

To keep the article concise, we have decided to explain more about preferences
in a future article. But for the curious, have a look at
[`/plugins/ticket-box`](https://gitlab.gnome.org/World/Phosh/phosh/-/tree/main/plugins/ticket-box?ref_type=heads)
to get an idea of how to create preferences for your plugin.

Similar to how we test plugins, you can test plugins using `plugin-prefs`.

```bash
$ G_MESSAGES_DEBUG="phosh-plugin-prefs-ticket-box" _build/tools/run_tool _build/tools/plugin-prefs
```

This should launch a standalone that can be used to test Ticket Box plugin.

{{< image name="plugin-prefs.png" title="Phosh plugin preferences" >}}

## Wrapping Up

Once your plugin is ready, you can package it and distribute it. If the plugin
is for general users, then you can open up a [merge
request](https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests) to make it
part of Phosh itself.

## Footnotes

[^1]:
    Technically speaking, you can write it in any language as long as you can
    compile to a form loadable by [GModule](https://docs.gtk.org/gmodule/).