Using D-Bus System Features in Sailfish OS
- Tutorial
Introduction
This article is a continuation of the material on the use of the system API in Sailfish OS and is devoted to the functions of D-Bus in this operating system. The interaction with the standard calendar and flash will be discussed in detail. A list of other basic functions of the D-Bus system is presented at the end of the article.
To understand the above material, you need to know the basics of development for Sailfish OS and the principles of interaction with D-Bus within the operating system. A good starting point is the relevant articles from FRUCT:
[1] Start of development for Sailfish OS ;
[2] Development for Sailfish OS: working with D-Bus .
Theory
There are two ways to get information about the available interfaces and D-Bus functions. The first approach is to study the interfaces registered in the system using special utilities (for example,
Visual D-Bus
and D-Bus Inspector
) or the command line (Figure 1). The second approach uses the methodology for studying the source code described in the previous article. 
[Figure 1 - An example of obtaining a list of D-Bus interfaces.]
A big plus of the first approach is the ability to obtain information about interfaces that are “wired” into binary files and are not available in text form, but only currently active interfaces can be analyzed in this way. The second approach used in this article inverts the described plus and minus of the first approach.
Equipment
D-Bus functions can be called (or defined) from C ++ code (which is not available in the system), from QML code and from application desktop files. Accordingly, when searching for information about interfaces, it is necessary to have an idea, firstly, about the module
org.nemomobile.dbus
; secondly, about the method of accessing D-Bus from desktop files. The QML module
org.nemomobile.dbus
provides two main components for working with D-Bus: DBusAdaptor
and DBusInterface
. The first allows you to create your own interface for the application, the second - use the existing one. In the general search for information, both components are of interest, since they allow you to find out how you can interact with the application from the outside, and how the application uses third-party interfaces, respectively.For example, to find out which interfaces D-Bus uses the settings application, you need to go to the directory
/usr/share/jolla-settings
and check for the use of D-Bus:grep -i -H 'dbus' * && grep -A 5 'DBusAdaptor' ./settings.qml
$ cd /usr/share/jolla-settings/
$ grep -i -H 'dbus' *
settings.qml:import org.nemomobile.dbus 2.0
settings.qml: DBusAdaptor {
$ grep -A 5 'DBusAdaptor' ./settings.qml
DBusAdaptor {
service: "com.jolla.settings"
path: "/com/jolla/settings/ui"
iface: "com.jolla.settings.ui"
function showSettings() {
At the same time, when analyzing desktop files, it must be remembered that, firstly, desktop files are stored in a directory
/usr/share/applications
; secondly, the use of the described functions launches the application instance; thirdly, when describing interaction with D-Bus, fields with a prefix are used X-Maemo
:X-Maemo-Service
- service, or location of the application on the user or system bus;X-Maemo-Object-Path
- the path or name of the object;X-Maemo-Method
- name of the called method.
Interesting to know
The prefixes

[Figure 2 - Dependence of Sailfish OS on other operating systems ( Wikipedia ).]
It is worth noting that in desktop files it is possible to use a field
X-Maemo
appeared in Sailfish OS as a legacy from the Maemo operating system (Figure 2), previously developed by Nokia. They allow you to declare D-Bus functions in such a way that they can be accessed without first starting the program. These functions allow you to launch the program with the implementation before opening some preliminary work. [Figure 2 - Dependence of Sailfish OS on other operating systems ( Wikipedia ).]
It is worth noting that in desktop files it is possible to use a field
MimeType
to indicate the types of files that the program can process. An example implementation is available on GitHub .Thus, to get a list of all applications that support starting using D-Bus, you need to go to the directory
/usr/share/applications
and search for one of the keywords:grep -H 'X-Maemo-Service' *
$ cd /usr/share/applications/
$ grep -H 'X-Maemo-Service' *
jolla-calendar-import.desktop:X-Maemo-Service=com.jolla.calendar.ui
jolla-calendar.desktop:X-Maemo-Service=com.jolla.calendar.ui
jolla-camera-viewfinder.desktop:X-Maemo-Service=com.jolla.camera
jolla-clock.desktop:X-Maemo-Service=com.jolla.clock
jolla-contacts-import.desktop:X-Maemo-Service=com.jolla.contacts.ui
jolla-email.desktop:X-Maemo-Service=com.jolla.email.ui
jolla-gallery-openfile.desktop:X-Maemo-Service=com.jolla.gallery
jolla-gallery-playvideostream.desktop:X-Maemo-Service=com.jolla.gallery
jolla-mediaplayer-openfile.desktop:X-Maemo-Service=com.jolla.mediaplayer
jolla-mediaplayer.desktop:X-Maemo-Service=com.jolla.mediaplayer
jolla-messages-openurl.desktop:X-Maemo-Service=org.nemomobile.qmlmessages
jolla-messages.desktop:X-Maemo-Service=org.nemomobile.qmlmessages
jolla-notes-import.desktop:X-Maemo-Service=com.jolla.notes
jolla-notes.desktop:X-Maemo-Service=com.jolla.notes
jolla-settings.desktop:X-Maemo-Service=com.jolla.settings
new-mail.desktop:X-Maemo-Service=com.jolla.email.ui
open-url.desktop:X-Maemo-Service=org.sailfishos.browser.ui
ovpn-import.desktop:X-Maemo-Service=com.jolla.settings
sailfish-office-openfile.desktop:X-Maemo-Service=org.sailfish.office
sailfish-office.desktop:X-Maemo-Service=org.sailfish.office
simkit.desktop:X-Maemo-Service=org.sailfish.simkit
voicecall-ui-openurl.desktop:X-Maemo-Service=com.jolla.voicecall.ui
voicecall-ui.desktop:X-Maemo-Service=com.jolla.voicecall.ui
A summary table of the basic system functions of the API and D-Bus is given at the end of the article.
Practice
The theoretical material presented in the current and previous articles allows you to implement your components to work with the system functions of D-Bus.
Create a component that allows you to open the schedule for the current day. To do this, go to the directory
/usr/share/jolla-calendar
(the principles of directory naming were described in the previous article) and find out in which files there is a call to D-Bus:grep -r -i -H 'dbus' *
$ cd /usr/share/jolla-calendar/
$ grep -r -i -H 'dbus' *
DbusInvoker.qml:import org.nemomobile.dbus 2.0
DbusInvoker.qml:DBusAdaptor {
calendar.qml:import org.nemomobile.dbus 2.0
calendar.qml: DbusInvoker {}
The result of the command shows that the definition of interfaces is made in a file
DbusInvoker.qml
that contains only definitions of the interface and D-Bus functions:cat ./DbusInvoker.qml -n
$ cat ./DbusInvoker.qml -n
1 import QtQuick 2.0
2 import Sailfish.Silica 1.0
3 import org.nemomobile.dbus 2.0
4 import Calendar.dateParser 1.0
5
6 DBusAdaptor {
7 service: "com.jolla.calendar.ui"
8 path: "/com/jolla/calendar/ui"
9 iface: "com.jolla.calendar.ui"
10
11 function viewEvent(id, recurrenceId, startDate) {
12 var occurrence = DateParser.parseTime(startDate)
13 if (isNaN(occurrence.getTime())) {
14 console.warn("Invalid event start date, unable to show event")
15 return
16 }
17
18 if (pageStack.currentPage.objectName === "EventViewPage") {
19 pageStack.currentPage.uniqueId = id
20 pageStack.currentPage.recurrenceId = recurrenceId
21 pageStack.currentPage.startTime = occurrence
22 } else {
23 pageStack.push("pages/EventViewPage.qml",
24 { uniqueId: id, recurrenceId: recurrenceId, startTime: occurrence },
25 PageStackAction.Immediate)
26 }
27 requestActive.start()
28 }
29
30 function viewDate(dateTime) {
31 var parsedDate = new Date(dateTime)
32 if (isNaN(parsedDate.getTime())) {
33 console.warn("Invalid date, unable to show events for date")
34 return
35 }
36
37 if (pageStack.currentPage.objectName === "DayPage") {
38 pageStack.currentPage.date = parsedDate
39 } else {
40 pageStack.push("pages/DayPage.qml", { date: parsedDate }, PageStackAction.Immediate)
41 }
42 requestActive.start()
43 }
44
45 function importFile(fileName) {
46 if (pageStack.currentPage.objectName === "ImportPage") {
47 pageStack.currentPage.fileName = fileName
48 } else {
49 pageStack.push("pages/ImportPage.qml", { "fileName": fileName }, PageStackAction.Immediate)
50 }
51 requestActive.start()
52 }
53
54 function activateWindow(arg) {
55 app.activate()
56 }
57 }
It can be seen from the adapter code that in the created component it is necessary to connect to the service
com.jolla.calendar.ui
and use the path /com/jolla/calendar/ui
and interface com.jolla.calendar.ui
(lines 7-9). After that, the declared functions will become available, of which, within the framework of the task, of interest is only viewDate
(lines 30-43), which takes as an argument one of the date representations recognized by the object Date
. The results obtained allow you to implement your component for working with the calendar:CalendarController.qml
import QtQuick 2.0
import Sailfish.Silica 1.0
import org.nemomobile.dbus 2.0
Item {
id: calendarControl
/* Открыть календарь для текущей даты.
*/
function showAgenda() {
calendar.call('viewDate', Date.now())
}
DBusInterface {
id: calendar
service: 'com.jolla.calendar.ui'
path: '/com/jolla/calendar/ui'
iface: 'com.jolla.calendar.ui'
}
}
By the same principle, other components are formed that interact with the functions of the D-Bus system.
Consider the flash control process. To do this, according to the analysis of the catalog
/usr/share/jolla-settings/pages/flashlight
, you need to connect to the service com.jolla.settings.system.flashlight
and use the path /com/jolla/settings/system/flashlight
and interface com.jolla.settings.system.flashlight
. After that, by calling the toggleFlashlight function without parameters, it becomes possible to turn the flash on and off. However, in some tasks it may be necessary to obtain information about the current state of the flash - whether it is on or off. To do this, use a function
getProperty
with a parameter passed to it "flashlightOn"
. In this case, a Boolean value is returned.grep -i -H 'dbus' ./pages/flashlight/* && grep -A 5 -i -H 'DBusInterface' ./pages/flashlight/Flashlight.qml
$ cd /usr/share/jolla-settings
$ grep -i -H "dbus" ./pages/flashlight/*
./pages/flashlight/Flashlight.qml:import org.nemomobile.dbus 2.0
./pages/flashlight/Flashlight.qml: flashlightDbus.call("toggleFlashlight", undefined, handleToggle, handleError)
./pages/flashlight/Flashlight.qml: property QtObject flashlightDbus: DBusInterface {
./pages/flashlight/Flashlight.qml: flashlight.flashlightOn = flashlightDbus.getProperty("flashlightOn")
$ grep -A 5 -i -H "DBusInterface" ./pages/flashlight/Flashlight.qml
./pages/flashlight/Flashlight.qml: property QtObject flashlightDbus: DBusInterface {
./pages/flashlight/Flashlight.qml- signalsEnabled: true
./pages/flashlight/Flashlight.qml- service: "com.jolla.settings.system.flashlight"
./pages/flashlight/Flashlight.qml- path: "/com/jolla/settings/system/flashlight"
./pages/flashlight/Flashlight.qml- iface: "com.jolla.settings.system.flashlight"
./pages/flashlight/Flashlight.qml- function flashlightOnChanged(newOn) {
Given the above, a component for interacting with the flash is implemented:
FlashlightController.qml
import QtQuick 2.0
import Sailfish.Silica 1.0
import org.nemomobile.dbus 2.0
Item {
id: flashlightControl
// Состояние вспышки.
property bool flashlightOn
// Включает или выключает вспышку.
function toggleFlashlight() {
flashlightOn = !flashlightOn;
flashlight.call("toggleFlashlight", undefined);
}
DBusInterface {
id: flashlight
service: "com.jolla.settings.system.flashlight"
path: "/com/jolla/settings/system/flashlight"
iface: "com.jolla.settings.system.flashlight"
signalsEnabled: true
function flashlightOnChanged(newOn) {
flashlightControl.flashlightOn = newOn
}
}
Component.onCompleted: {
flashlightControl.flashlightOn = flashlight.getProperty("flashlightOn")
}
}
Conclusion
This article describes two ways to find information about D-Bus functions in Sailfish OS, and one of them is analyzed in detail - search in the source code. With its use, examples of components for interacting with the flash and the standard calendar are developed and commented on. The code for these and other modules is available on GitHub .
However, do not forget that some tasks can be solved by simply running the program of interest with the required arguments. For example, launching a standard browser with opening a site can be done using the command
sailfish-browser https://google.com/
. But this is beyond the scope of the material described in the article.sailfish-browser https://google.com/
$ sailfish-browser https://google.com/
[D] unknown:0 - Using Wayland-EGL
greHome from GRE_HOME:/usr/bin
libxul.so is not found, in /usr/bin/libxul.so
Created LOG for EmbedLite
[D] onCompleted:103 - ViewPlaceholder requires a SilicaFlickable parent
Loaded xulDir:/usr/lib/xulrunner-qt5-38.8.0/libxul.so, appDir:/usr/bin
EmbedLiteExt virtual nsresult EmbedChromeManager::Observe(nsISupports*, const char*, const char16_t*):82: obj:(nil), top:app-startup
EmbedLiteExt virtual nsresult EmbedTouchManager::Observe(nsISupports*, const char*, const char16_t*):86: obj:(nil), top:app-startup
EmbedLiteGlobalHelper app-startup
EmbedLiteSyncService app-startup
PREFS SERVICE INITAILIZED
EmbedPrefService app-startup
EmbedliteDownloadManager initialized
UserAgentOverrideHelper app-startup
1505073762747 addons.manager DEBUG Application has been upgraded
1505073762892 addons.manager DEBUG Loaded provider scope for resource://gre/modules/addons/XPIProvider.jsm: ["XPIProvider"]
1505073762912 addons.manager DEBUG Loaded provider scope for resource://gre/modules/LightweightThemeManager.jsm: ["LightweightThemeManager"]
1505073762942 addons.manager DEBUG Loaded provider scope for resource://gre/modules/addons/GMPProvider.jsm
1505073762961 addons.manager DEBUG Loaded provider scope for resource://gre/modules/addons/PluginProvider.jsm
1505073762968 addons.manager DEBUG Starting provider: XPIProvider
1505073762973 addons.xpi DEBUG startup
1505073762982 addons.xpi DEBUG checkForChanges
1505073762993 addons.xpi DEBUG Loaded add-on state from prefs: {}
1505073763000 addons.xpi DEBUG getInstallState changed: false, state: {}
1505073763009 addons.xpi DEBUG Empty XPI database, setting schema version preference to 16
1505073763012 addons.xpi DEBUG No changes found
1505073763015 addons.manager DEBUG Registering shutdown blocker for XPIProvider
1505073763021 addons.manager DEBUG Provider finished startup: XPIProvider
1505073763022 addons.manager DEBUG Starting provider: LightweightThemeManager
1505073763024 addons.manager DEBUG Registering shutdown blocker for LightweightThemeManager
1505073763029 addons.manager DEBUG Provider finished startup: LightweightThemeManager
1505073763032 addons.manager DEBUG Starting provider: GMPProvider
1505073763046 addons.manager DEBUG Registering shutdown blocker for GMPProvider
1505073763050 addons.manager DEBUG Provider finished startup: GMPProvider
1505073763052 addons.manager DEBUG Starting provider: PluginProvider
1505073763055 addons.manager DEBUG Registering shutdown blocker for PluginProvider
1505073763059 addons.manager DEBUG Provider finished startup: PluginProvider
1505073763060 addons.manager DEBUG Completed startup sequence
Created LOG for EmbedPrefs
[D] QMozWindowPrivate::setSize:71 - Trying to set empty size: QSize(-1, -1)
Attempting load of libEGL.so
EmbedLiteExt virtual nsresult EmbedTouchManager::Observe(nsISupports*, const char*, const char16_t*):86: obj:0xb225a130, top:domwindowopened
EmbedLiteExt void EmbedChromeManager::WindowCreated(nsIDOMWindow*):91: WindowOpened: 0xb225a140
EmbedLiteExt void EmbedTouchManager::WindowCreated(nsIDOMWindow*):95: WindowOpened: 0xb225a140
EmbedLiteExt void EmbedTouchManager::WindowCreated(nsIDOMWindow*):108: id for window: 1
###################################### SelectAsyncHelper.js loaded
###################################### embedhelper.js loaded
### ContextMenuHandler.js loaded
### SelectionPrototype.js loaded
### SelectionHandler.js loaded
Init Called:[object Object]
JavaScript warning: https://www.google.ru/xjs/_/js/k=xjs.mhp.en_US.2vKAz7DqmvI.O/m=sb_mobh,hjsa,d,csi/am=AAAD/rt=j/d=1/t=zcms/rs=ACT90oFx8AHVqc9lMfPQBwURKXyQ4qaFiA, line 7: mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create
The main system API functions:
Description | Required data |
---|---|
Create atmosphere |
|
Adjust screen brightness |
|
Screen orientation adjustment |
|
Automatically adjust screen brightness |
|
Setting the sleep time |
|
Setting the display status while charging |
|
Setting the system font size |
|
System Volume Adjustment |
|
Vibration setting |
|
Turn on / off sounds on system events |
|
Enable / Disable WLAN |
|
Enable / Disable Internet Sharing |
|
Turn on / off flight mode |
|
Turn on / off bluetooth |
|
Main system D-Bus functions:
Description | Required data |
---|---|
View calendar events | Service: com.jolla.calendar.ui Path: /com/jolla/calendar/ui Interface: com.jolla.calendar.ui Function: viewEvent(id, recurrenceId, startDate) |
View the day on the calendar | Service: com.jolla.calendar.ui Path: /com/jolla/calendar/ui Interface: com.jolla.calendar.ui Function: viewDate(dateTime) |
Opening the camera in the last state | Service: com.jolla.camera Path: / Interface: com.jolla.camera.ui Function: showViewfinder() |
Opening the front camera | Service: com.jolla.camera Path: / Interface: com.jolla.camera.ui Function: showFrontViewfinder() |
Create an alarm | Service: com.jolla.clock Path: / Interface: com.jolla.clock Function: newAlarm() |
View contact | Service: com.jolla.contacts.ui Path: /com/jolla/contacts/ui Interface: com.jolla.contacts.ui Function: showContact(int contactId) |
Contact Editing | Service: com.jolla.contacts.ui Path: /com/jolla/contacts/ui Interface: com.jolla.contacts.ui Function: editContact(int contactId) |
Import contacts | Service: com.jolla.contacts.ui Path: /com/jolla/contacts/ui Interface: com.jolla.contacts.ui Function: importWizard() |
Play audio file by URL | Service: com.jolla.mediaplayer Path: /com/jolla/mediaplayer/ui Interface: com.jolla.mediaplayer.ui Function: openUrl(url) |
Create a new note | Service: com.jolla.notes Path: / Interface: com.jolla.notes Function: newNote() |
View Settings | Service: com.jolla.settings Path: /com/jolla/settings/ui Interface: com.jolla.settings.ui Function: showSettings() |
View download list | Service: com.jolla.settings Path: /com/jolla/settings/ui Interface: com.jolla.settings.ui Function: showTransfers() |
View Account List | Service: com.jolla.settings Path: /com/jolla/settings/ui Interface: com.jolla.settings.ui Function: showAccounts() |
View call recording settings | Service: com.jolla.settings Path: /com/jolla/settings/ui Interface: com.jolla.settings.ui Function: showCallRecordings() |
Enable / Disable Android Support | Service: com.jolla.apkd Path: /com/jolla/apkd Interface: com.jolla.apkd Function: controlService(true/false) |
Turn on / off flash | Service: com.jolla.settings.system.flashlight Path: /com/jolla/settings/system/flashlight Interface: com.jolla.settings.system.flashlight Function: toggleFlashlight() |
Reboot device | Service: com.nokia.dsme Path: /com/nokia/dsme/request Interface: com.nokia.dsme.request Function: req_reboot() |
Turn off the device | Service: com.nokia.dsme Path: /com/nokia/dsme/request Interface: com.nokia.dsme.request Function: req_shutdown |
To call | Service: com.jolla.voicecall.ui Path: / Interface: com.jolla.voicecall.ui Function: dial(number) |
Open images in gallery | Service: com.jolla.gallery Path: /com/jolla/gallery/ui Interface: com.jolla.gallery.ui Function: showImages(array_of_urls) |
Open video in gallery | Service: com.jolla.gallery Path: /com/jolla/gallery/ui Interface: com.jolla.gallery.ui Function: playVideoStream(url) |
Create a new letter | Service: com.jolla.email.ui Path: /com/jolla/email/ui Interface: com.jolla.email.ui Function: mailto() |
WLAN Search | Service: com.jolla.lipstick.ConnectionSelector Path: / Interface: com.jolla.lipstick.ConnectionSelectorIf Function: openConnectionNow('wifi') |
Questions and ideas that arise during development can always be discussed in the Telegram chat and in the VKontakte group .