A splash window has no title, no decorations, and no window manager borders around it. It's not draggable and it does not have a close button. Large applications that loads many shared libraries and create complicated windows usually take a while to get ready and prepare their main window, so the “splash window” with just the application's name, in pretty colors, appears quickly, up front. A splash window provides immediate feedback when launching the application.
The usual approach involves launching the application launched indirectly. The initial loader is a small program that quickly shows the splash window, and does nothing else except starting another process that runs and initializes the main application. The launcher process terminates, and the splash window disappears, when the main application window opens for business.
splash.C
shows a basic splash window containing
nothing but a simple “Loading...” message, with a gradient
background. splash.C
pauses for two seconds, to
simulate a large application getting loaded, then starts another example
program:
table2.C
from the section called “Adjustable tables”.
splash.C
creates a pipe and attaches it to
table2.C
's file descriptor 3.
table2.C
closes its file descriptor 3 after it
finishes creating and showing its main window.
splash.C
waits for the pipe to close, then
terminates itself, closing its splash window.
/* ** Copyright 2019-2021 Double Precision, Inc. ** See COPYING for distribution information. */ #include "config.h" #include <x/exception.H> #include <x/destroy_callback.H> #include <x/appid.H> #include <x/w/main_window.H> #include <x/w/main_window_appearance.H> #include <x/w/gridlayoutmanager.H> #include <x/w/gridfactory.H> #include <x/w/label.H> #include <x/w/text_param_literals.H> #include "splash.H" #include <x/pidinfo.H> #include <x/forkexec.H> #include <x/fditer.H> #include <string> std::string x::appid() noexcept { return "splash.examples.w.libcxx.com"; } // Creator for the splash window, factored out for readability. void create_splash(const x::w::main_window &main_window) { auto glm=main_window->gridlayout(); x::w::gridfactory f=glm->append_row(); // Not much of a splash window. Just a large, black "Loading..." // label. f->create_label({ "serif; point_size=48"_theme_font, x::w::black, "Loading..." }); } x::w::main_window create_mainwindow(const options &options) { // main_window's create() takes an optional initial parameter that // precedes the creator lambda, which is x::w::main_window_config // by default. // // Passing in an x::w::transparent_splash_window_config or a // x::w::splash_window_config creates a splash window. x::w::transparent_splash_window_config transparent_splash_config; // transparent_splash_window_config creates a splash window with a // transparent background color, ostensibly for properly displaying // a rounded border around the contents of the splash window. // // splash_window_config creates a normal non-transparent window. // // transparent_splash_window_config inherits from splash_window_config, // and if the display screen does not have an alpha channel // (for transparency), it ends up creating a normal, non-transparent // window by using its splash_window_config superclass. x::w::splash_window_config &splash_config=transparent_splash_config; // We specify a custom appearance of the splash window, with // a custom background color, a vertical gradient // // This background color also gets used for the transparent window as // well. This sets the background color for the internal container // that's just inside the transparent splash window's borders. The // splash window's background color is transparent, hence it appears // to have rounded borders. The application should not use // set_background_color() with a transparent main_window, but rather // specify the apparent background color of the splash window in the // splash_config. splash_config.appearance=splash_config.appearance->modify ([] (const x::w::main_window_appearance &custom_appearance) { custom_appearance->background_color= x::w::linear_gradient{0, 0, 0, 1, 0, 0, { {0, x::w::silver}, {1, x::w::white}, {2, x::w::silver} }}; }); // splash_window_config's border member specifies an ordinary, non- // rounded border. // // This is an extra field in the splash_window_config that's not a // part of its appearance object. x::w::border_infomm square_border; square_border.color1=x::w::black; square_border.width=.5; square_border.height=.5; splash_config.border=square_border; // Its transparent_splash_window_config also has a "border", for the // transparent splash window, if one ends up getting created, so // we configure the same border there, except that it's rounded. x::w::border_infomm rounded_border=square_border; rounded_border.rounded=true; rounded_border.hradius=1; rounded_border.vradius=1; transparent_splash_config.border=rounded_border; // main_window_config's (inherited) "name" gives the main window's // name (defaults to "main"). This example program starts another // program with a main window. If this example program opened a // a 2nd main window, in addition to the splash one, they must use // different names, so this is not strictly needed here: transparent_splash_config.name="splash"; // After passing either an x::w::splash_window_config or a // x::w::transparent_splash_window_config to main_window's create(), // the next parameter is the creator lambda, as usual. if (options.square->value) return x::w::main_window::create(splash_config, create_splash); return x::w::main_window ::create(transparent_splash_config, create_splash); } x::fd spawn_application() { auto me=x::exename(); // My path // Compute the path to the compiled "table2" program in the same // directory. me=me.substr(0, me.rfind('/')+1) + "table2"; x::forkexec fe{me}; // Attach a pipe to file descriptor 3. // // table2 closes file descriptor 3 when it finishes initialization. x::fd pipe=fe.pipe_from(3); fe.spawn_detached(); // The object for the write end of the pipe is still in the forkexec // object. Return from here destroys it, so only the read side of // the pipe is open in this process. The write side of the pipe return pipe; } void splashwindow(const options &opts) { x::destroy_callback::base::guard guard; auto main_window=create_mainwindow(opts); main_window->on_disconnect([] { _exit(1); }); guard(main_window->connection_mcguffin()); main_window->show_all(); sleep(2); auto pipe=spawn_application(); // Now read from the pipe until file descriptor 3 is closed. x::fdinputiter b{pipe}, e; while (b != e) ++b; } int main(int argc, char **argv) { try { options opts; opts.parse(argc, argv); splashwindow(opts); } catch (const x::exception &e) { e->caught(); exit(1); } return 0; }
auto main_window=x::w::main_window::create( x::w::splash_window_config{}, [&] (const x::w::main_window &mw) { // ... });
x::w::main_window
's
create
() has an optional parameter
that precedes the creator lambda.
Passing an
x::w::main_window_config
parameter (the default parameter if not specified)
creates a normal application window.
Passing an
x::w::transparent_splash_window_config
creates a splash window instead of a normal application window.
The created x::w::main_window
behaves
normally, except for the following differences:
No title, dragging, or normal window manager decorations
Splash windows use X protocol's override-redirect flag to shed the title bar and the close button from the display's window manager. The on_delete() callback that normally responds to the close button will never get called, so there's no purpose to installing it.
Position and appearance
Splash windows appear above other windows (with most window managers), and always appear centered on the display.
x::w::splash_window_config
creates
a plain, rectangular splash window with a custom border.
x::w::transparent_splash_window_config
creates a splash window with a transparent background.
This provides the means for drawing a rounded border around the
contents of the splash window.
x::w::transparent_splash_window_config
inherits from
x::w::splash_window_config
, and uses it
to create a plain rectangular splash window if the display
server does not provide an alpha channel for transparent windows.
Default splash window background and border
Both
x::w::splash_window_config
and
x::w::transparent_splash_window_config
contain
several fields that control the splash window's appearance.
They inherit from x::w::main_window_config
,
including its
appearance object, whose
background_color
field sets the splash
window's background color.
Supplementing the appearance object,
both
x::w::splash_window_config
and
x::w::transparent_splash_window_config
contain a border
that sets the splash window's
border; with
x::w::transparent_splash_window_config
default theme border being typically a rounded border, and
x::w::splash_window_config
having a plain border; and in this manner displays that do not
have a non-alpha channel will also have
x::w::splash_window_config
's border
also, due to
x::w::transparent_splash_window_config
inheriting from it.
x::w::transparent_splash_window_config
also uses the
background_color
from the appearance object
to draw the default background inside its border.
A transparent splash window's background gets set to the transparent
color, by definition, for the benefit of its rounded border.
For this reason, a splash window should not have its background
color modified with set_background_color
,
after its creation.
Set the splash window's background color only using a custom
appearance object when
creating the splash window.