So You Want to Write a LightDM Greeter…

What is a LightDM Greeter?

LightDM is a lightweight display manager that splits the responsibilities of a display manager between the server and the UI, which is known as a greeter.  When you login to Ubuntu you are shown the Unity Greeter, but all the back-end session management and authentication is provided by the LightDM daemon, and functionality that a greeter needs is provided by liblightdm. LightDM exposes a set of APIs that allow you easily and quickly write your own greeter using your choice of languages.  As long as you can interact with LightDMs GObject API, you can use any language you want.

Why Write a Greeter?

Given all that, why would you want to write a greeter?  The Unity Greeter looks pretty nice after all.  In my case, I had special requirements that necessitated a change to the UI and some extra processing for the session.  During the course of this work, I wrote a greeter based on the sample GTK greeter that comes with LightDM and then applied my modifications.  I originally wrote it in C, but then moved to Python for easier integration into my other code.  My hope is that you can re-use some of my learnings below and write your own greeter that suits the needs of your distro or project.

The Unity Greeter

Let’s Get Started

This post is designed to give you an overview of the greeter and how it works. The code for my very simple example greeter, which is available here, is commented to the point where I hope it will answer your code questions. After reading this post, walk through the code and I think the process will make sense. Once you understand this code and want to do more advanced things, you should check out the GTK example greeter, which is part of the LightDM GTK+ Greeter project.

Note: You can also get my code from launchpad here, or via bzr with bzr branch lp:~mfisch/+junk/example-greeter

How LightDM Authentication Works

The first thing to understand is the way LightDM authenticates is a multi-step process and that this process will guide how we write our greeter.

  1. User enters a username and clicks the Login button.
  2. LightDM passes the username to PAM and responds back to the greeter with a prompt, such as “Password:”.
  3. User enters the password and the greeter passes it back to LightDM.
  4. LightDM authenticates with PAM and returns success or failure back to the greeter.
  5. LightDM may also return a message, such as “Login failed”, which needs to be displayed to the user.
  6. If the authentication succeeds, the greeter starts a session.

Program Flow

The diagram below shows the flow between the greeter, the top row, and the LightDM backend, the bottom section. This flow assumes a successful login as we don’t show the failure case for simplicity’s sake.

Flow of the greeter during login

Looking at the Code

At this point you probably want to look at the code and compare it to the flow in the diagram. The code is heavily commented and hopefully the diagram makes it easy to follow.

Screenshots of the Example Greeter

As you can see our greeter isn’t pretty, but it works. Hopefully this gives you an idea of the prompt re-use, which is pretty standard in greeters I’ve seen. Making this look nice is left as an exercise to the artistic reader.

Installing Your Greeter

Your greeter will minimally include an executable and a desktop file. The executable is usually installed somewhere in the path, like /usr/bin. The .desktop file goes into /usr/share/xgreeters and tells LightDM how to launch your greeter. The name of the .desktop file defines what you need to put in LightDM’s conf file. Additionally your greeter may install a configuration file, typically in /etc/lightdm and a Gtk UI file, if you’re using GTK. Once your greeter is in place you need to tell LightDM to use it. If you’re just testing things, you can edit /etc/lightdm/lightdm.conf and set greeter-session=example-greeter. What you set here has to match the name of your desktop file as mentioned above. If you plan to do this in a package install, you need to use /usr/lib/lightdm-set-defaults, which allows you to set a few defaults via a script. In this case we’d call /usr/lib/lightdm/lightdm-set-defaults –greeter=example-greeter. You can run that script with no arguments to see it’s full capabilities and options.

Once you install your greeter, you need to restart LightDM with sudo initctl restart lightdm. If it works, great! If not, check out the Debugging section below.

Debugging

A few hints on debugging your greeter. Anything you print to stderr in your greeter ends up in /var/log/lightdm/x-0-greeter.log. I find that keeping that open in a separate console dedicated to looking at this log always helps. Since the logs get deleted every time the greeter restarts, this is your best option: sudo tail -f /var/log/lightdm/x-0-greeter.log

LightDM itself may have useful logs if your configuration is broken, they’re in /var/log/lightdm/lightdm.log, and again you need sudo to view the logs.

Debugging a greeter with a debugger can be tricky, so I’ve found that printing debug into to stderr is your best option. However, the greeter seems simple enough that this method usually works fine.

Also you almost always want to do your development of a greeter in a VM. Alternatively, you can run lightdm in test mode with lightdm –test-mode, which allows you to run lightdm from the command-line as an unprivileged user. This will start your greeter in a window inside your existing session.

Finally you may get your greeter into a state where it keeps trying to launch and keeps failing. In a VM this will result in the window popping between X and a text terminal as it keeps failing. Just wait a bit and LightDM will eventually give up on your greeter and you can drop into a console and see what’s wrong.

Documentation

LightDM’s API is defined here. Everything I used in the example greeter focuses on the Greeter section. If you want to do more advanced things like allow the user to shutdown the system from the greeter, or query the list of available sessions, please check the other sections.

I also highly recommend walking through the GTK Greeter for seeing how some of these more advanced options work.

A word of caution if you’re going to use Python, in version 1.0.6 of LightDM, the introspection bindings for Python were broken. They’re fixed on trunk, but I don’t think a fix has made it into a release yet (as of Feb 6, 2012).

Summary

This example code barely covers the surface of what you need to do in order to make a good greeter, but it should help you get started. I recommend for follow-up that you read through example the GTK example greeter, which comes in the source for the LightDM package. You can use that knowledge to make your greeter look much nicer and add features like accessibility (a11y) and options like shutdown/restart/etc from your greeter.

Tagged , , ,

16 thoughts on “So You Want to Write a LightDM Greeter…

  1. [...] Fischer wrote an interesting article about how to write a LightDM greeter. The post is really well done, explaining how LightDM works internally and how to get the greeter [...]

  2. Joost says:

    Hi there, very nice tutorial! I might give it a try.
    On the side: do you know of any sites or projects that make custom LightDM greeters available for download?

  3. wangchengcai says:

    hi,

    I want to write my own greeter and test is in real machine not a virtual machine and without and restart, but I do not know how to do it………….

    • Matt Fischer says:

      You can restart lightdm with sudo initctl restart lightdm after setting it to use your greeter. Another option is running lightdm in test mode by running lightdm –test-mode. Check out the lightdm manpage for more details.

  4. Michael Rawson says:

    Thanks for this Matt-great guide.

    Just a couple of points for those using the –test-mode option.

    -lightdm –test-mode –debug gives you more verbose output.

    -if you use –test-mode, lightdm logs your greeter to $HOME/.cache/lightdm/log/x-2-greeter.log

  5. Implementing a greeter can also be achieve more easily using lightdm-webkit-greeter for anybody who is familiar with Web technologies (HTML / Javascript).

    Here is an sample :
    https://github.com/jfbrazeau/lightdm-webkit-pretty-greeter

    And here is a screenshot :
    https://raw.github.com/jfbrazeau/lightdm-webkit-pretty-greeter/master/screenshot.jpg

  6. Tim says:

    Hello Greeter Creators,

    I am here because I am considering writing my own greeter for Ubuntu 12.04, but I am first hoping to save time and just modify Unity. Maybe I should post this on a Ubuntu forum, but it seems your blog, Matt, is close to where I need to be, so I hope you’ll be patient with some digression here. After reading this, can you tell me if I need to just write my own greeter or otherwise how I can modify Unity as suggested below?

    I like the aesthetics of Unity Greeter but I do not like how you can change settings like volume without having to log in, and how the screen blanks out after a certain time, despite disabling all known forms of suspend and hibernation and setting all power policies I know to ‘do nothing’. (BTW, I light-heartedly joke, in the spirit of Peter Griffin — You know what really grinds my gears? Why should a greeter have control over my display and give random passersby the ability to jack with my settings, and even invite them to type messages on my personal computer with a ‘leave a message’ button? I need more control and security here because my machine is not for public use.)

    At any rate, I hope to modify Unity greeter to:

    1) Disable all controls & indicators except those essential to logging, logging out, switching users, and shutting down. So, no volume control, no time/date display, no language changing, no nothing.

    2) Disable screen blanking entirely (even if it burns my screen). (I have already disabled every power-saving feature in Ubuntu, uninstalled every suspend and hiberation package…What actually works?)

    Which files controls these things and what new code or adjustments to code are required? Once modified is a compile required? Will creating my own greeter solve these problems?

    Thanks,

    Tim

    • Matt Fischer says:

      I can at least help with #1. You need to disable the loading of the plugins in the menubar. A simple hack for this is to modify the function load_indicator_library(). Just hack the names_to_try like change “lib” to “fred” and it won’t load any. That may also solve #2 but I’m not sure.

      • Tim says:

        Thanks for the prompt suggestion! Which file contains the load_indicator_library() function? Again, I’m using Ubuntu 12.04 and new to greeters. (I did a grep -r “load_indicator_library()” / and found nothing.) I’ve noticed for some reason I often don’t have the same files as others with my distro… LightDM is installed and is the current version and everything. :)

        • Matt Fischer says:

          You need to be looking at the unity-greeter source. Lightdm does not present a UI. Look in the vala files.

          • Tim says:

            In settings-daemon.vala I found a line that says:

            GLib.Bus.own_name (GLib.BusType.SESSION, “org.gnome.ScreenSaver”

            And just above that line it says: /* We want to block the screensaver from being activated by g-s-d or any of the indicators. So we own the name, preventing dbus activation by anyone else. If the screensaver were allowed to start, it would disable X’s builtin blanking logic which we do use and instead, blanking would require gnome-session and it’s Presence DBus interface to be run. */

            I’m a bit fuzzy on how the code is telling my computer to activate X’s builtin blanking logic and I find no mention of it besides this one place in this file. I see a couple of places I might be able to disable some unwanted plugins.

            I really appreciate your tips! Open to more, thanks.

  7. Shane says:

    Just out of curiosity, what was the ‘extra processing for the session’ that you mentioned..?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>