#Sxmo: Simple X Mobile - User Guide

Project Overview | Install Guide | User Guide | System Guide | Contributing | Images | Demo Video

Documentation (postmarketOS Stable) | Documentation (postmarketOS edge) | Documentation (Development Version)


After login, you will be presented the SXMO interface as follows:


The core of the Sxmo UI is based on:

  • a tiling window manager (sway if you are running on Wayland, and dwm if you are running Xorg)
  • a menu program (bemenu on Wayland, dmenu for Xorg),
  • a gesture deamon for the touchscreen (lisgd)
  • a virtual keyboard (wvkbd on Wayland, svkbd on Xorg)

Sxmo runs on either Xorg or Wayland, with different but very similar software to make it possible. You may switch between the two environment via the Toggle WM option in the Power menu (provided you have both installed).

Regardless of the environment you use Sxmo consists in a large set of POSIX shell scripts that glue all these tools together. All these shell scripts comply to the pattern sxmo_*.sh and can be found in your /usr/bin/ directory. A lot of functionality is also in hooks sxmo_hook_*.sh and can be found in /usr/share/sxmo/default_hooks/ or ~/.config/sxmo/hooks.

#Status Bar

The status bar located at the top displays the various workspaces that you have in the form of the numbers 1,2,3,4. (Inactive workspaces are not shown.) Tapping one of these numbers will take you to that workspace. If you are running dwm rather than sway, you will see right next to it the layout that is activated (see layouts). The default layout is a vertical stack (three lines).

At the top-right you see the status icons:

  • A signal bar icon shows that you have a GSM connection and what strength it is.
  • GSM icons shows that you have a data connection (2G/3G/4G)
  • The wifi icon indicates you are connected to a wireless network and what strength it is
  • The battery icon shows your battery status and whether it is charging or not (small lightning symbol)
  • Volume is expressed through the speaker icons.
    • When you have the earpiece as audio output, you see a phone handle icon with sound waves
    • When you have headphones as audio output, you see a headphone icon
  • An icon also represents what "state" the device is in: unlock (open circle), lock (circle with slash), screenoff (filled circle), or proximity lock (circle with dot)
#Global UI Controls

Button Bindings

The three hardware buttons on the Pinephone thus can trigger 9 different actions. You have to type multiple times or to hold the button to access other actions.

The default button bindings are:

  • Volume Raise:
  • Volume Lower:
    • 1 tap: Toggle virtual keyboard (wvkbd/svkbd)
    • 2 taps: Toggle the window manager layout algorithm (between monocle/tile/bstack on dwm)
    • 3 taps: Kill client
  • Power button:

Swipe gestures

In addition to the button bindings, a custom application called lisgd was developed to provide touchscreen swipe gestures within Sxmo. These gestures are sensitive to the edge of the screen where the gesture is initiated or where they end up, and some are sensitive to the length/distance of the swipe. Gestures in the main part of the screen, staying clear of the edges, are usually not interpreted and passed to the underlying application unmodified (assuming it has gesture support).

The SXMO gestures are visualized in the following schematic:


The default swipe gestures are:

  • 1 finger Right-to-Left from Right edge: Focus next tag/workspace
  • 1 finger Left-to-Right from Left edge: Focus previous tag/workspace
  • 2 fingers Right-to-Left (anywhere): Move focused application to previous tag/workspace
  • 2 fingers Left-to-Right (anywhere): Move focused application to next tag/workspace
  • 1 finger Top-to-Bottom along the Left edge (held pressed): Volume down
  • 1 finger Bottom-to-Top from the Top edge: Show the application menu
  • 2 finger Bottom-to-Top from the Top edge: Show the system menu
  • 1 finger Top-to-Bottom onto the Top edge: Close the active menu
  • 1 finger Bottom-to-Top from the Bottom edge: Show virtual keyboard
  • 1 finger Top-to-Bottom onto the Bottom edge: Hide virtual keyboard
  • 2 finger Top-to-Bottom onto the Bottom edge: Close the current active window
  • 3 finger Top-to-Bottom onto the Bottom edge: Kill the current active window
  • 1 finger from Bottom-Right corner, swiping diagonally: Rotate the screen
  • 1 finger from Bottom-Left corner, swiping diagonally: Lock the device
  • 1 finger Left-to-Right along the top edge (held pressed): Increase screen brightness
  • 1 finger Right-to-Left along the top edge (held pressed): Decrease screen brightness

There are various default gestures that translate to keypresses for the underlying application, this facilitates navigation in a variety of applications, including terminal-based applications, without needing the virtual keyboard:

  • 1 finger Right-to-Left onto the Left edge: Send Left arrow
  • 1 finger Left-to-Right onto the Right edge: Send Right arrow
  • 1 finger Top-to-Bottom along the Right edge (held pressed): Send Key down (scroll down)
  • 1 finger Bottom-to-Top along the Right edge (held pressed): Send Key up (scroll up)
  • 1 finger Right-to-Left along the Bottom edge: Send Backspace
  • 1 finger Left-to-Right along the Bottom edge: Send Return

The sensitivity of the gestures can be controlled, see: user-customizable functionality.

#The Menu System

Menus are a central feature of Sxmo and are navigable through using the Pinephone's 3 hardware buttons:

The default menu bindings for the Pinephone buttons are:

  • Volume Raise: Previous item
  • Volume Lower: Next item
  • Power: Select item

You can also simply use the touchscreen to tap your selection if you'd like as well.

The menus are essentially scripts around bemenu or a custom patched version of dmenu. Note that while using a menu, the hardware buttons have different behaviour than when no menu is running. If you use sway, this mode is explicitly indicated by a red "Menu" block in the top bar. In dwm, the button bindings won't be triggered as these grab's are setup to be mutually exclusive from X's point of view.

Tip: You can close any open menu with a gesture, swipe straight up (vertically) onto the top edge of the screen and all the open menu will close.

#Included Menus

1. Application-specific context menus

The application-specific context menu (triggered by single tapping the volume raise key) lets you access application-specific features of the currently focused window. For example while using mpv, the application-specific context menu lets you pause the video, increase/decrease volume, seek, etc. You can reference the sxmo_appmenu.sh script for a full list of functionality.

2. Global system menu (Sys)

The global system menu (triggered by double tapping the volume raise button) lets you launch applications, toggle system preferences and more. This is probably the closest thing to 'homescreen' in traditional phone OS's in that it can be the starting point to access much of the functionality in Sxmo. This menu lets you:

  • Launch Scripts and Applications
  • Make/Receive Calls and Texts
  • Launch the Camera
  • Connect to Wifi and Cellular data (2G/3G/4G)
  • Connect to Bluetooth (if bluez is installed)
  • Adjust audio output device
  • Adjust modem settings

3. Global config menu (Config)

The global config menu is accessible by launching the global system menu aforementioned and selecting Config. This menu let you:

  • Adjust system brightness
  • Rotate the screen
  • Upgrade packages
  • Edit your configuration (your custom profile)

This section applies to dwm (Xorg) only:

DWM is a dynamic window manager with a master-slave stack layout. As such, the window manager automatically decides where windows should be placed. The algorithm used to decide where windows should be placed is governed by the icon to the right of the workspace number. Open some windows and you should get an understanding of the various layouts. By default, the layout is set the vertical stack layout and tapping icon representing the current layout will cycle through the available layouts.

When the monocle layout is active, it will only show one window that takes up the entire workspace. By tapping the left and right hand side of the title bar, you can cycle back and forth between the windows that are open.

For more info on DWM and other layouts that you can patch in, see the upstream website for dwm.


There are five states:

  • Unlocked (unlock): Screen is on; touchscreen is enabled.
  • Locked (lock): Screen is on; touchscreen is disabled.
  • Screenoff (screenoff): Screen is off; touchscreen is disabled. There is a short purple blink while in this state.
  • Proximity Lock (proximitylock/unlock): When close to your face, the screen will be off and touchscreen disabled; when far from your face, screen will be on and touchscreen enabled. This is used during phone calls, for instance.
  • Suspend or Crust: This is the kernel CRUST.

Do note that locking at this stage merely means the screen is off and touchscreen disabled. We do not yet have a security check for unlocking, such as passphrase entry. This feature is planned soon.

schema of the lock states when pressing power

The power button will wake the phone from the deep sleep ("crust") mode to the "unlock" mode one at a time. While unlocked, power button will move the phone directly to "screenoff" mode.

When the phone is considered idle (no input, nor playing video, etc), the phone will slowly go to deep sleep ("crust") one state after some time (~8 seconds). If you do not want this automatic deep sleep behaviour you can override some hooks (see: hooks). You can also toggle these in System -> Config.

Deep sleep can always be accessed manually via the menu: System -> Power -> Suspend .

Note that if you receive notifications in any of these states, the green LED will be enabled.

When you are in deep sleep mode, you can exit this mode and restore the above bindings by clicking the powerkey once. This places the device in "lock" state. Clicking the powerkey again transitions to "unlock" state. (This prevents accident "butt" unlocks.)

To determine if the phone can suspend into CRUST, sxmo relies on the hook sxmo_hook_wakelocks.sh. For instance, an active ssh connection will set a wakelock so the device won't suspend. You can override or replace those with your own custom rules.


Sxmo ensures that cron jobs run and will actively wake the phone from sleep temporarily to this end. The cron daemon is installed but not enabled in postmarketOS. Cron has to be started manually (rc-service crond start) and set to start on boot (rc-update add crond default). We use a little program called mnc to wake the phone up before the next planned cron job. We also wrap some sxmo logic in a dedicated script called sxmo_rtcwake.sh which:

  • manages the screenlock state while doing the task
  • puts the phone back to crust when done
*/15 * * * * sxmo_rtcwake.sh sleep 10 2>> ~/.local/state/sxmo.log

This example will wake the phone up for 10 seconds every 15 minutes. You may want to redirect the standard error output to the main log as shown in the example above.

If you omit sxmo_rtcwake.sh for a job, the system will not wake up from crust. Note that in such cases, you might want to use sxmo_wm.sh execwait instead, e.g.:

*/15 * * * * sxmo_wm.sh execwait sleep 20 2>> ~/.local/state/sxmo.log

This will make sure that the SXMO environmental variables are sent to your script.

#Calls and Texting

Calling and texting is fully functional and should work out-of-the-box. Make sure you have the modem killswitch in the enabled position and wait a little bit after booting before trying modem functionality to allow the modem to connect.

Modem functionality is based on using the menu system and accessible through the global system menu. You'll need to explicitly toggle the modem there to receive calls/texts. If your SIM is locked, you must unlock it manually. The scripting behind the scenes works via ModemManager using the mmcli command line tool.

If you have issues with delayed or not receiving smses, you can follow this to debug:

Modemmanager can get stuck/miss certain texts if they have unexpected content. To check if this is the case, make sure sxmo_modemmonitor.sh is running to monitor for new texts and run: mmcli -m any --messaging-list-sms. If some sms are listed, that means modemmonitor is stuck. You can view the content of these sms via mmcli once and they will be removed forever.

It might be worth submitting the contents of these sms (be careful to protect the privacy of you and your friends) or other debug logs to modemmanager issue tracker. It will also help upstream debug your issue if you enable modemmanager logs and provide modemmanager with logs for the problematic text. Enabling modemmanager logs is worthwhile if you often have issues with telephony and need upstream support for missing texts.

Unlocking SIM

As long as your SIM is locked, a lock icon should appear in the status bar. SXMO automatically asks for your SIM's PIN code using a menu (since sxmo 1.4.1).

Alternatively, you can do so from the command-line as follows:

mmcli -i 0 --pin 1234

You could put this in your unlock sim hook (~/.config/sxmo/hooks/sxmo_hook_modem.sh), but there is of course a significant security risk involved if your device gets compromised!


To place a new call, you can use the Dialer entry in the global system menu. You will be prompted for a number to dial. Once the call connects, a menu will automatically be launched which let's you:

  • Manage audio routing
  • Send DTMF (dial) tones
  • Hang up the call

A proximity lock is automatically enabled that will lock and turn off your screen during a call if you have the phone close to your ear.


To compose a new text message, from the Texts entry you will see a Send a Text entry which first prompt you for a number. After entering the destination number you will by default be dropped into a vim-like editor (vis) to compose your message. Once your message is as you'd like it, exit the editor using ZZ/:wq!. You will now be taken to a new menu to confirm your message from which you can edit/send/add recipients/add attachments/cancel the message.

To view existing text message threads you can use the Texts entry in the global system menu. This menu will let you tail follow a logfile for your conversation with each number. When a new text is sent or received; the tail will automatically be updated with the new text contents.

While displaying the conversation you can pop out a contextual menu with power up button to reply by text or to start a call with the number.

You can also open a "conversation" window with a gesture from the botton edge. It will open your editor and the virtual keyboard to type your sms. Save and close the file to send the sms. A new editor will be openned again to type a new message.

Monitoring for Incoming Calls/Texts

A vital feature of a working phone is being able to receive new texts and pickup calls. This functionality is made possible through a script that monitors the modem activities and vibrates the phone and blinks the green LED when there is an incoming text/call. This functionality is optional and can be toggled on/off (e.g. to have a 'silent' mode) via the Config menu.

While a call is incoming:

  • The vibration motor will trigger for 3 seconds
  • The green LED will trigger
  • A menu will appear to allow you to pickup the call. You can also discard the call or mute the ring. If you missed the menu, you can also open either the global or application menu and you'll see a menu entry to pickup the call; of course this is time-sensitive and this menu entry will only be visible while the other party's line is ringing

When a new text message comes in:

  • The vibration motor will trigger rapidly in 3 intervals for 300ms
  • The green LED will trigger If you are in a locked/suspended state the LED may turn cyan, white, yellow
  • To view the new text message, refer to the Texting section above

Configuring GSM

To have a working gsm connection you can use the dedicated Networks submenu entry "Add a GSM Network". You then must type the APN your provider gave you. You can then toggle this GSM entry as other network manager ones.

Configuring MMS

MMS messaging should work just like regular text messaging. When you Send a Text there will be the option to add multiple recipients or attachments. To make mms work, sxmo relies on mmsd-tng. The main configuration will be located in ~/.mms/modemmanager/mms. To make things easier in sxmo, we have a dedicated menu entry in Configuration called Config MMS. This menu will create a default config and you then can edit fields one by one. The script should take care of restarting mmsd when closed.

Note that you likely will not have to configure mmsd-tng, if your settings are already in the database. Consider contributing your own if it is not.

Note that your carrier's nameserver must be present in /etc/resolv.conf in order to send/receive mms. This should be automatic. However, sometimes NetworkManager will place the wifi's nameservers above the carrier's nameservers, and since /etc/resolv.conf can only use the first three entries, the carrier's nameservers will not be used. To fix this, you can set dns=none in /etc/NetworkManager/NetworkManager.conf and use a static /etc/resolv.conf instead.

Contacts System

The Sxmo contacts system based on a plain TSV file that can be placed at $XDG_CONFIG_HOME/sxmo/contacts.tsv. This TSV file is expected to have two tab separated columns: phonenumber, and contactname. Upon receiving a call if you have a contact stored associated with the incoming number, the contact name will appear instead of the number. Also contact names will appear in the Texts and Dialer menus if they are present in the contacts TSV file. If no contacts.tsv is present, or the number is missing from this file; the contact in menus will show up as ???. An contacts.tsv example might look like:

+122345628	John Smith
+128371642	Jeff Foo
+31612345678	Jan Janssen

Dedicated Menu

There is a script named "Contacts" accessible from the main menu to manage those contacts. You can add, edit and delete all of your contacts.

International Numbers

Note that you should always prefix numbers you call out with, text to, or add to the contact system with their international prefix code and with the initial plus sign. The contact app menu will softly force you to specify your contacts with the leading country code. Note that you can still specify an "invalid" phone number (by example 123 or 888 or whatever your provider use).

Behind the scenes of mmcli, numbers sometimes come into the system with international prefixes and sometimes without. We think that this issue only happens with local phone numbers from the country your provider is in. So if you recieve a call from the number 54321 for example; it could come into mmcli as +154321 or as 54321 if this was a US number. To manage this, we use an environment variable named DEFAULT_COUNTRY to indicate which country your provider is. By example, if you are in France, you should configure this in your profile export DEFAULT_COUNTRY=FR. Then Sxmo will handle any non-prefixed incoming phone number as a French one and add the +33 prefix automatically. You then can be assured that texts / outgoing / incoming calls will line up in regards to deduplication of contacts in menus and text message threads will stay intact.

#Included Scripts and Applications

In the global system menu there are entries for both applications and scripts.

Included Scripts:

  • Web Search: Search duckduckgo with the query provided by the user (bangs work too)
  • Files: A filebrowser that can handle opening audio and text files
  • Timer: A simple countdown timer script that vibrates the phones upon completion
  • Youtube: Search youtube by keyword in dmenu and then view in mpv (script based on idiotbox)
  • Youtube (audio): Search youtube by keyword in dmenu and then listen in mpv (script based on idiotbox)
  • Weather: United States weather forecast (by zipcode) dmenu script
  • RSS: Aggregates RSS feeds and let's you view by timespan dmenu script (based on sfeed)

Supported Applications:

The application menu supports a wide variety of applications, and will only show them if installed. For some of these applications special context menus are availables. Some of the notable examples are (not exhaustive):

  • St: The suckless terminal
  • Foot: The minimalistic wayland terminal
  • Firefox: The infamous FOSS browser often symbolized by a fox
  • Surf: The suckless minimalistic browser based on Webkit
  • Netsurf: An alternative minimalistic browser that renders really fast
  • Lagrange: A gemini browser
  • Sacc: A great minimalistic gopher browser; launches by default to a good phlog aggregator (optional)
  • Vim/Neovim/Vis: A modal terminal-based text editor
  • Feh/Sxiv: Image viewers for X
  • Mpv: Video player
  • Nano: A simple text-based text editor
  • Mutt/Neomutt: A text-based mail client
  • W3m: A text-based browser with vim-like keybindings
  • Weechat: A text-based IRC client and much more
  • Ncmpcpp: A text-based music client for MPD
  • Cmus: Another terminal-based music player
  • Aerc: A simple terminal-based mail client
  • Xcalc: A nice (and fast) calculator app

There is a menu entry in the global system menu (Networks -> Add a WPA Network) to connect to wifi. This is essentially this is just a wrapper to launch nmtui. If your phone has a wifi killswitch (like the Pinephone or Librem 5), make sure it is in the enabled position.

#Mobile data

Mobile data can be simarly added via the menu (Networks -> Add a GSM Network). It will ask for an APN, you may also consult the postmarketOS pinephone documentation for that aspect.

#Audio Routing

You can use the Audio entry in the global system menu to toggle which audio output you want to send sound to.

Note that when in a call, the audio device selected in the global system menu won't automatically apply; rather audio will automatically be initially routed to the earpiece and then changeable through the in call menu. Upon the call ending, audio is always routed back to the headphone jack.

#Bluetooth, Pipewire, and Pulseaudio Support

You can also choose to start pipewire from your start hook. To use sxmo's scripts with pulseaudio/pipewire instead of alsa, also install pamixer from the postmarketOS repos. The pulseaudio/pipewire support is really minimal at this time. Call audio still use the megi c code and rely on direct alsa manipulation.

There is a postmarketos-ui-sxmo-bluetooth package in postmarketOS that will automatically install and configure pipewire, wireplumber, and bluetooth.

Currently, bluetooth audio during phone calls does not work. Please see:

#Updating and Changelog

Sxmo's packages are currently distributed through packages in pmOS so when new package versions are periodically pushed; your install can be

To update run:

apk update
apk upgrade -aiv

There is also a menu entry within the Config menu to update as well which runs the same commands as above.

For details on what changed between package versions or image releases refer to the changelog.

#User Customizable Functionality
#General Settings

All files listed below should be in $XDG_CONFIG_DIR (usually: ~/.config/sxmo/).

Filepath Description
profile This file is loaded before starting dwm or sway. You should use it to configure environment variable. Note that /etc/profile.d/* and your own $HOME/.profile will be loaded before by tinydm.
xinit Automatically executed script executed upon starting X. (not used for Sway/Wayland).
sway Sway configuration file (not used for dwm/Xorg), sets key bindings, wallpaper etc... You can also trigger commands in it with "exec".

TSV file wherein each row is: contactnumber TAB contactname

If unset all contacts will show up as 'Unknown Number'

All phone numbers must be full phone numbers startings with + and the country code


TSV file wherein each row is: blockedcontactnumber TAB blockedcontactname

All phone numbers must be full phone numbers startings with + and the country code

If a text or call from a blocked number is detected, it is sent to the $XDG_DATA_HOME/sxmo/block folder

No notifications are sent and no hooks are ran for texts.

No notifications are sent and the call is muted for calls.

sfeedrc Sfeedrc file (see sfeed documentation used by RSS script)
userscripts Directory or file to place user scripts which will automatically appear in the menu system

If a user-defined hook file does not exist on activity, sxmo will run the corresponding project defined default hook from /usr/share/sxmo/default_hooks/. For example, if you pickup a call and $XDG_CONFIG_HOME/sxmo/hooks/sxmo_hook_pickup.sh does not exist, /usr/share/sxmo/default_hooks/sxmo_hook_pickup.sh will be run.

Note also that some hooks will be in a subdirectory with a devicename. For instance, in /usr/share/sxmo/default_hooks/ there are one_button_ereader and three_button_touchscreen and various names linked to them. (We determine the name of your device by looking at /sys/firmware/devicetree/base/compatible.) This allows you to have unique hooks depending on the kind of device that you are running.

Here are some (but not all) hooks available!

hooks/sxmo_hook_start.sh This is a good place to start some daemons

Executable script to run when the phone is receiving a call / rings

This script is called with "$1" set to the contact name or incoming number if not in contacts.


Executable script to run when the phone is accepting an incoming call.


Executable script to run when you hangup the phone.


Executable script to run when the phone missed an incoming call

This script is called with "$1" set to the contact name or incoming number if not in contacts.


Executable script to run when the phone is receiving a text, mms, or vvm (visual voice mail)

This script is called with "$1" set to the contact name or incoming number if not in contacts and "$2" the actual text.

As well, if this is a Visual Voice Mail or an MMS, "$3" will be set to the payload ID.

Finally, if this is a Group Text, "$4" will be set to the group contact name or number if not in contacts.


Executable script to run when the phone has just sent a text

This script is called with "$1" set to the number (or contact name) and "$2" the actual text.


This script contains various rules for programs that should block suspend.


This script contain methods to update some status bar components. See SYSTEMGUIDE

hooks/sxmo_hook_apps.sh Executable script to run when display of the app menu is requested, outputs to stdout and allows you to override the default app menu (see sxmo_appmenu.sh)
hooks/sxmo_hook_scripts.sh Executable script to run when display of the scripts menu is requested, outputs to stdout and allows you to override the default app menu (see sxmo_appmenu.sh)
hooks/sxmo_hook_postwake.sh Executable script that is executed after waking from suspension.
hooks/DEVICENAME/sxmo_hook_lock.sh Executable script that is executed prior to locking the device
hooks/DEVICENAME/sxmo_hook_unlock.sh Executable script that is executed immediately after unlocking the device
hooks/sxmo_hook_lisgdstart.sh Script that is executed to start the gesture deamon, overrides the defaults (see ``sxmo_lisgdstart.sh``). This allows defining custom gestures.
hooks/sxmo_hook_stop.sh Executable script that is executed immediately after closing the window manager (dwm/sway)
hooks/DEVICENAME/sxmo_hook_inputhandler.sh Script that is executed when a gesture is to be interpreted. It is passed the WM_CLASS of the active window as first parameter and the identifier/name of the gesture (or command to run) in the second argument, as configured with lisgd. See ``sxmo_inputhandler.sh`` for details. This script allows you to define your own context-sensitive (i.e. application specific) gestures.
hooks/sxmo_hook_discard.sh This script is executed (asynchronously) when you discard an incoming call
hooks/sxmo_hook_mute_ring.sh This script is executed (asynchronously) when you mute an incoming call
hooks/sxmo_hook_notification.sh This script will run whenever any kind of notification is received. It can be used for example to blink the led if you want to override the default behaviour
hooks/sxmo_hook_modem.sh This hook will run when the modem changes state. This is where you can use custom code if the SIM is locked. You can consider putting something like ``mmcli -i 0 --pin 1234`` in it to unlock automatically, if you don't mind the negative security implications that carries in case your device gets compromised.
hooks/sxmo_hook_restart_modem_daemons.sh This hook will run when the modem daemons are restarted.
hooks/sxmo_hook_desktop_widget.sh This script is run after the window manager starts to provide a desktop widget (like a clock)
hooks/sxmo_hook_suspend.sh This script is run when system suspends. It contains the actual suspend call.
hooks/sxmo_hook_rotate.sh This script is called when we rotate. $1 is the new orientation (normal, left, right).
hooks/sxmo_hook_icons.sh This script is called every time we load a script. You can override icons here.
hooks/sxmo_hook_contextmenu.sh This script is called when a menu is loaded. You may override or add new menu options here.
hooks/sxmo_hook_tailtextlog.sh This hook displays the sms log for a numbers passed as $1.
hooks/DEVICENAME/sxmo_hook_inputmenu.sh This script is called when a (hardware) button is pressed or a touchscreen gesture occurs. You can override the default button mappings here.

Note: $XDG_CONFIG_HOME by default is equal to ~/.config

`$XDG_STATE_HOME/sxmo.log` The central log for Sxmo. Various sxmo scripts output a message here via the `sxmo_log` function in `sxmo_common.sh`.
`$XDG_STATE_HOME/tinydm.log` Contains standard error output from various programs running in your sessions if you are using `tinydm`.
`$XDG_STATE_HOME/superd.log` Logs the start of various sxmo (and other) background processes.
`$XDG_CACHE_HOME/sxmo/youtubehistory.tsv` This log file will save all the terms you've searched for using the youtube script.

Note: $XDG_STATE_HOME is ~/.local/state/ by default. $XDG_CACHE_HOME by default is equal to ~/.cache

#Environment Variables

The following environment variables can be set in ~/.config/sxmo/profile:

Environment variable Description
$TERMCMD Terminal to launch on double-clicking power button and used in scripts. Defaults to `foot` (wayland) or `st` (Xorg).
$BROWSER Browser to launch on triple-clicking/holding power-button and used in scripts. Defaults to `surf`.
$KEYBOARD Keyboard to launch on single-clicking power button and used in scripts. Defaults to `svkbd-mobile-intl` or `svkbd-sxmo`
$KEYBOARD_ARGS Arguments to pass to $KEYBOARD, e.g., `-o | clickclack -f /usr/share/sxmo/keytap.wav`
$EDITOR Editor to use to handle files (partial support; full support plans for composing texts etc). Defaults to `vis`.
$SXMO_RECDIR Directory that the Record script will save recordings to.
$SXMO_SUBREDDITS Subreddits (comma-separated) to appear in menu for Reddit script.

Files of GPS coordinates to populate the locations menu in the foxtrotgps menu.

Each file is expected to be a tsv; the first entry being the location; the second being lat, lon pair.

$SVKBD_ENABLEOVERLAYS Boolean, set to 0 to disable the overlay functionality on the virtual keyboard (svkbd) (enabled by default), the overlay functionality is responsible for showing input variations such as diacritics when holding a key with a long press.
$SVKBD_LAYERS Comma separated list of layers to enable on the virtual keyboard. See the svkbd source for your layout for a definition of available layers.
$SVKBD_HEIGHTFACTOR Integer value expressing a height fraction, a one key row of the virtual keyboard takes 1/x of the screen height.
$DMENU_WRAP_AROUND Boolean value specifying whether dmenu interfaces should wrap around to the top/bottom of the list while scrolling. Set to `true` to enable (disabled by default).
$SXMO_LISGD_THRESHOLD Integer expressing the distance a gesture much minimally have to be recognized (unit corresponds to pixels usually)
$SXMO_LISGD_THRESHOLD_PRESSED Integer expressing the distance a gesture much minimally have to be recognized for gestures that act when pressed (such as volume/brightness control and scrolling) (unit corresponds to pixels usually)
$SXMO_THRESHOLD Integer expressing the time in milisecond between two input button press to consider them as one action row
$DEFAULT_COUNTRY String to indicate the default country sxmo should fallback to when the phone numbers are not country code prefixed. Should be set to a country code (iso-3166?) such as ``FR`` for France, ``DE`` for Germany, ``US`` for the Unites States.

The best place to set these default environment variables is in your ~/.profile or in ~/.config/sxmo/profile if they are sxmo specific.

Other environmental variables that are more device specific can be found in README.md file in deviceprofiles/ in the source. For information on adding a new device, see below.

#Update migrations

While developing Sxmo, we will regularly update certain configuration files such as the xinit/sway template, the hooks or whatever. These files are typically a mixture of changes by us and customizations by the user. This mixture gives the user maximum flexibility to adapt Sxmo to their liking. However, when we update such files, the challenge is to ensure that user modifications can be easily merged back in again. Moreover, we must ensure the system is never in a broken state because of outdated configurations and version mismatches.

Whenever your configuration files are out-of-date when starting Sxmo, they will be moved aside (i.e. renamed with .needs-revision extension) and the default configuration will take its place. A red notification will pop up telling you have configuration files that need to be migrated. This migration is done by running a script named sxmo_migrate.sh. This script can simply be launched from the configuration menu or via ssh (recommended). It first shows the differences between your configuration and the new default, and allows you to edit and apply your configuration accordingly. sxmo_migrate.sh use $DIFFTOOL to help you merge your changes. By default $DIFFTOOL is set to vimdiff.

If you have any pending migrations, always make sure to complete the migration process before making any new changes to your configuration. It is also recommended to keep your configuration under version control (e.g. git).

Techical details:

Sxmo (since 1.8.1) uses explicitly versioned configuration files, meaning that they each carry a simple version hash unique to the file. This version hash is expressed in a comment in the file itself, such as:

# configversion: d8aaf01c9489793bda3686ef23b2b192

You should only update this version hash when sxmo_migrate.sh prompts you to do so by showing a diff of a newer configversion hash.

If you want to see what files are disabled and need migration, run sxmo_migrate.sh state, or run sxmo_migrate.sh sync state if you just performed an upgrade and haven't restarted yet. If you want to revert all your configuration files to the default, then you can run sxmo_migrate.sh reset. This is usually a last resort if you end up with a broken system and can be considered a kind of factory reset, all your configuration files will moved out of the way and flagged for migration then.

The process that checks the versions of your configuration files is sxmo_migrate.sh sync, it runs automatically when Sxmo starts.

#Resolving system configs on system upgrade and make

Apk will install new configs as .apk-new on upgrades if you have modified the original config in /etc. Moreover, when hacking on Sxmo, you will often run make installand this may "modify" a config in /etc from apk's perspective. You can merge apk's config changes by running doas update-conf. You can also run apk audit to list all the files that have changed from what apk originally installed.

#X resources

When running Xorg/dwm, certain interface parameters, such as the font size for dmenu, can be configured through X resources. Create a file ~/.Xresources and you have the following notable settings to tweak:


Set to the font and fontsize you want for all menus (dmenu). Defaults to Terminus-30.

#User Scripts

User scripts are custom scripts the user can run via the global system menu. To add your own custom userscript, you have two options: edit the userscripts file or place a shell script in the userscripts directory.

  • Option 1. Edit $XDG_CONFIG_HOME/sxmo/userscripts and write your entries in it, following the appmenu format <name> ^ <should-return-to-menu> ^ <script-path-or-command> one entry per line. Example:  Weather ^ 0 ^ sxmo_terminal.sh -f "monospace:size=5" sh -c "curl http://wttr.in/ | less -SR"
  • Option 2. Create the $XDG_CONFIG_HOME/sxmo/userscripts directory and place your .sh scripts in the userscripts directory. Note, Userscripts should be set to be executable. You can set a title for the script by adding a comment line of the following ofrmat near the top of the file:
# title="$icon_glb My World"

For examples of scripts Sxmo users have made for their mobile devices, see:

#Further Customization

Much of Sxmo's core-functionality in regards to menus are built out via plain shell scripts. So further cutomization should be simple. See sxmo-util's scripts directory to get a better sense of how things are put together. You can edit the scripts on your system for temporary fixes and please consider contributing your changes if you believe your modifications may be useful to other users.


The sxmo_files.sh script (accessible via sxmo_appmenu.sh) follows the XDG MIME Applications standard. We have our own custom xdg-open implementation called sxmo_open.sh that will parse the mimeapps.list files and open the default application as set by the user. To change a default application review the format of the mimeapps.list and edit ~/.config/mimeapps.list.


We use tinydm as login manager. The tinydm goal is to simply automatically login a target user on boot. You can configure the UID to login as in /etc/conf.d/tinydm. (make sure to adapt this if you create a custom user!)

Tinydm logs to $XDG_STATE_HOME/tinydm.log by default. This is also where standard error output from other programs running in your setting may end up and a good place to check in addition to sxmo.log when debugging.


SXMO just provides you with a simple graphical environment on top of your favourite distribution, which by default is postmarketOS for SXMO. PostmarketOS is in turn based on Alpine Linux. You can install any packages your distribution provides from the command line as follows:

$ apk update
$ apk add name-of-the-package

To see a categorized list of applications that work well with Sxmo and install the apps via a gui, install and use the appstore.sh userscript.

The built-in application menu of sxmo is only aware of a subset of applications, and will only show them when installed, feel free to add more tools to the menus and submit a patch.


This section describes how to add a new device to SXMO. There are three basic steps:

  • Determine your SXMO_DEVICE_NAME
  • Add a sxmo_deviceprofile_SXMO_DEVICE_NAME.sh file to scripts/deviceprofiles/ in the source tree.
  • Add (or symlink to an existing) SXMO_DEVICE_NAME folder in configs/default_hooks/ in the source tree.
#Determining the SXMO_DEVICE_NAME

The SXMO_DEVICE_NAME is determined by the following code in sxmo_init.sh

tr -c '\0[:alnum:].,-' '_' < /proc/device-tree/compatible | tr '\0' '\n' | head -n1
#Add deviceprofile file

In the source tree navigate to scripts/deviceprofiles/ and make a file called sxmo_deviceprofile_SXMO_DEVICE_NAME.sh. This file should contain various shell variables that define things unique to your device, e.g., input ids, etc. There is a README.md in the same directory that will help.

#Add a device folder

In addition to the deviceprofile file, which defines things like touch input ids, etc., you will also want to set a locking workflow for the device. We have three basic defaults to which all the devices symlink. Navigate to configs/default_hooks/ in the source tree. You will see there are three folders and several symlinks. These folders contain various hooks that handle locking mechanisms. There are at present three basic folders: three_button_touchscreen, one_button_e_reader, and desktop. You can also create your own, but usually you'll just want to symlink to one of these.

About this wiki

commit f79b95ca5ecee26919243c001bc763358924140d
Author: Maarten van Gompel <proycon@anaproy.nl>
Date:   2024-05-03T11:14:29+02:00

updated logging information
Clone this wiki
https://git.sr.ht/~anjan/sxmo-docs (read-only)
git@git.sr.ht:~anjan/sxmo-docs (read/write)