How to create a custom splash screen for a program?

I am currently building a client for our users at work with Ubuntu MATE 15.10 and Plank as a dock. But when I click for example the Firefox icon in the dock nothing happens until it suddenly pops up after >10 seconds, no loading icon as a mouse pointer or something like that.

Now is there a way to make a custom splash screen like the one in LibreOffice? Or just create a window like "Firefox is being started..." which closes once the application is open?

Thanks!


Create a splash window

You can use GTK's gtk_window_set_decorated() to create a splash window without (any) decorations. Combined with gtk_window_set_position(), you can pretty much create a custom splash screen.

An example

(script1, the splash window):

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, Pango

class Splash(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="splashtitle")
        maingrid = Gtk.Grid()
        self.add(maingrid)
        maingrid.set_border_width(80)
        # set text for the spash window
        label = Gtk.Label("Eat bananas while you are waiting for Firefox")
        label.modify_font(Pango.FontDescription('Ubuntu 22'))
        maingrid.attach(label, 0, 0, 1, 1)

def splashwindow():
    window = Splash()
    window.set_decorated(False)
    window.set_resizable(False)  
    window.set_position(Gtk.WindowPosition.CENTER)
    window.show_all()
    Gtk.main()

splashwindow()

which creates a splash screen like:

enter image description here

Of course, you can set any background colour, font and fontsize, images etc, depending on your taste, but this is the basic idea.

Make the splash screen disappear if the application's window appears

To kill the splash screen once the application's window appears, you'll need a script to wait for the application window, and (indeed) kill the process that runs the window.

(script2, the wrapper)

#!/usr/bin/env python3
import subprocess
import time

# set the application below
application = "firefox"
# set the path to the splash script below
path = "/path/to/splash_screen.py"

subprocess.Popen([application])
subprocess.Popen(["python3", path])

while True:
    time.sleep(0.5)
    try:
        pid = subprocess.check_output(["pidof", application]).decode("utf-8").strip()
        w_list = subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8")
        if pid in w_list:
            splashpid = [l.split()[2] for l in w_list.splitlines()\
                         if "splashtitle" in l][0]
            subprocess.Popen(["kill", splashpid])
            break
    except subprocess.CalledProcessError:
        pass

How to use

  1. The script (2) needs wmctrl:

    sudo apt-get install wmctrl
    
  2. Copy script1 (the splash screen) into an empty file, save it as splash_screen.py. Change if you want the text for the splash screen (but why would you :) )

    label = Gtk.Label("Eat more bananas while you wait for Firefox")
    
  3. Copy script2 into an empty file, save it as splash_wrapper.py In the head section of the script, change the path in the line:

    path = "/path/to/splash_screen.py"
    

    into the actual path (between quotes)

  4. Now run the setup by the command:

    python3 /path/to/splash_wrapper.py
    

    and your splash screen will appear if you run the wrapper, it will disappear once Firefox actually starts.


Notes

As mentioned the example above is quite straightforward. Of course you can make it much smoother, pimp the splash screen in all possible ways, or even make it semi- transparent:

enter image description here

(code:)

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, Pango

class Splash(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="splashtitle")
        maingrid = Gtk.Grid()
        self.add(maingrid)
        maingrid.set_border_width(80)
        # set text for the spash window
        label = Gtk.Label("Eat bananas while you are waiting for Firefox")
        label.modify_font(Pango.FontDescription('Ubuntu 22'))
        maingrid.attach(label, 0, 0, 1, 1)

def splashwindow():
    window = Splash()
    window.set_decorated(False)
    window.set_resizable(False)
    window.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0,0,0,1))
    window.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("grey"))
    window.set_opacity(0.8)
    window.set_position(Gtk.WindowPosition.CENTER)
    window.show_all()
    Gtk.main()

splashwindow()

or include an image:

enter image description here

(code:)

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, Pango

class Splash(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="splashtitle")
        maingrid = Gtk.Grid()
        self.add(maingrid)

        image = Gtk.Image()
        # set the path to the image below
        image.set_from_file("/path/to/image.png")
        maingrid.attach(image, 1, 0, 1, 1)

        maingrid.set_border_width(40)
        # set text for the spash window
        label = Gtk.Label("Eat bananas while you are waiting for Firefox")
        label.modify_font(Pango.FontDescription('Ubuntu 15'))
        maingrid.attach(label, 0, 0, 1, 1)

def splashwindow():
    window = Splash()
    window.set_decorated(False)
    window.set_resizable(False)
    window.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0,0,0,1))
    window.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("grey"))
    window.set_opacity(0.8)
    window.set_position(Gtk.WindowPosition.CENTER)
    window.show_all()
    Gtk.main()

splashwindow()

and so on...

Furthermore, you can make the application and the text arguments of both scripts etc, but this is the basic idea.

No icon in Unity / tasklist?

If you do not want an icon to appear in Unity (or any other task manager, like Plank), you can simply add a line to the __init__ section:

self.set_skip_taskbar_hint(True)