summaryrefslogtreecommitdiff
path: root/Userland/Services/WindowServer/main.cpp
blob: 94a7fd91cb566caa8f64be4bfd577c17fcf57ca4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "AppletManager.h"
#include "Compositor.h"
#include "EventLoop.h"
#include "Screen.h"
#include "WindowManager.h"
#include <LibCore/ConfigFile.h>
#include <LibCore/DirIterator.h>
#include <LibCore/File.h>
#include <LibGfx/Palette.h>
#include <LibGfx/SystemTheme.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int, char**)
{
    if (pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc sigaction", nullptr) < 0) {
        perror("pledge");
        return 1;
    }

    if (unveil("/res", "r") < 0) {
        perror("unveil /res");
        return 1;
    }

    if (unveil("/tmp", "cw") < 0) {
        perror("unveil /tmp cw");
        return 1;
    }

    if (unveil("/etc/WindowServer.ini", "rwc") < 0) {
        perror("unveil /etc/WindowServer.ini");
        return 1;
    }

    if (unveil("/dev", "rw") < 0) {
        perror("unveil /dev rw");
        return 1;
    }

    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_flags = SA_NOCLDWAIT;
    act.sa_handler = SIG_IGN;
    int rc = sigaction(SIGCHLD, &act, nullptr);
    if (rc < 0) {
        perror("sigaction");
        return 1;
    }

    auto wm_config = Core::ConfigFile::open("/etc/WindowServer.ini");
    auto theme_name = wm_config->read_entry("Theme", "Name", "Default");

    auto theme = Gfx::load_system_theme(String::formatted("/res/themes/{}.ini", theme_name));
    VERIFY(theme.is_valid());
    Gfx::set_system_theme(theme);
    auto palette = Gfx::PaletteImpl::create_with_anonymous_buffer(theme);

    auto default_font_query = wm_config->read_entry("Fonts", "Default", "Katica 10 400");
    auto fixed_width_font_query = wm_config->read_entry("Fonts", "FixedWidth", "Csilla 10 400");

    Gfx::FontDatabase::set_default_font_query(default_font_query);
    Gfx::FontDatabase::set_fixed_width_font_query(fixed_width_font_query);

    WindowServer::EventLoop loop;

    if (pledge("stdio video thread sendfd recvfd accept rpath wpath cpath proc", nullptr) < 0) {
        perror("pledge");
        return 1;
    }

    // First check which screens are explicitly configured
    {
        AK::HashTable<String> fb_devices_configured;
        WindowServer::ScreenLayout screen_layout;
        String error_msg;

        auto add_unconfigured_devices = [&]() {
            // Enumerate the /dev/fbX devices and try to set up any ones we find that we haven't already used
            Core::DirIterator di("/dev", Core::DirIterator::SkipParentAndBaseDir);
            while (di.has_next()) {
                auto path = di.next_path();
                if (!path.starts_with("fb"))
                    continue;
                auto full_path = String::formatted("/dev/{}", path);
                if (!Core::File::is_device(full_path))
                    continue;
                if (fb_devices_configured.find(full_path) != fb_devices_configured.end())
                    continue;
                if (!screen_layout.try_auto_add_framebuffer(full_path))
                    dbgln("Could not auto-add framebuffer device {} to screen layout", full_path);
            }
        };

        auto apply_and_generate_generic_screen_layout = [&]() {
            screen_layout = {};
            fb_devices_configured = {};
            add_unconfigured_devices();
            if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
                dbgln("Failed to apply generated fallback screen layout: {}", error_msg);
                return false;
            }

            dbgln("Applied generated fallback screen layout!");
            return true;
        };

        if (screen_layout.load_config(*wm_config, &error_msg)) {
            for (auto& screen_info : screen_layout.screens)
                fb_devices_configured.set(screen_info.device);

            add_unconfigured_devices();

            if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
                dbgln("Error applying screen layout: {}", error_msg);
                if (!apply_and_generate_generic_screen_layout())
                    return 1;
            }
        } else {
            dbgln("Error loading screen configuration: {}", error_msg);
            if (!apply_and_generate_generic_screen_layout())
                return 1;
        }
    }

    auto& screen_input = WindowServer::ScreenInput::the();
    screen_input.set_cursor_location(WindowServer::Screen::main().rect().center());
    screen_input.set_acceleration_factor(atof(wm_config->read_entry("Mouse", "AccelerationFactor", "1.0").characters()));
    screen_input.set_scroll_step_size(wm_config->read_num_entry("Mouse", "ScrollStepSize", 4));

    WindowServer::Compositor::the();
    auto wm = WindowServer::WindowManager::construct(*palette);
    auto am = WindowServer::AppletManager::construct();
    auto mm = WindowServer::MenuManager::construct();

    if (unveil("/tmp", "") < 0) {
        perror("unveil /tmp");
        return 1;
    }

    // NOTE: Because we dynamically need to be able to open new /dev/fb*
    // devices we can't really unveil all of /dev unless we have some
    // other mechanism that can hand us file descriptors for these.

    if (unveil(nullptr, nullptr) < 0) {
        perror("unveil");
        return 1;
    }

    dbgln("Entering WindowServer main loop");
    loop.exec();
    VERIFY_NOT_REACHED();
}