#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static constexpr ui::Color TASKBAR_COLOR = ui::Color::from_rgb(83, 83, 83); static OwnedPtr launcher_client; void sigchld_handler(int) { wait(nullptr); } void sigquit_handler(int) { // Reload the taskbar by exec-ing the executable, resetting everything. StringView args[] = { "/usr/bin/taskbar" }; os::Process::exec(args[0], { args, 1 }); } Result create_widget_group_for_app(ui::HorizontalLayout& layout, StringView path, StringView icon) { auto* button = TRY(make(ui::Rect { 0, 0, 50, 50 })); layout.add_widget(*button); auto* container = TRY( make(ui::Rect { 0, 0, 50, 50 }, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center)); button->set_widget(*container); button->set_action([=] { os::Launcher::LaunchDetachedRequest request; SET_IPC_STRING(request.command, path.chars()); launcher_client->send_async(request); }); auto image = TRY(ui::ImageWidget::load(icon)); container->set_widget(*image); image.leak(); return {}; } struct ApplicationFile { String name; String command; String icon; }; Vector s_app_files; // Pretty much copied from init.cpp. static Result load_application_file(const os::Path& path) { os::println("[taskbar] reading app file: %s", path.name().chars()); auto file = TRY(os::ConfigFile::open(path)); ApplicationFile app_file; app_file.name = TRY(String::from_string_view(file->read_string_or("Name", ""))); if (app_file.name.is_empty()) { os::println("[taskbar] app file is missing 'Name' entry, aborting!"); return {}; } app_file.command = TRY(String::from_string_view(file->read_string_or("Command", ""))); if (app_file.command.is_empty()) { os::println("[taskbar] app file is missing 'Command' entry, aborting!"); return {}; } app_file.icon = TRY(String::from_string_view(file->read_string_or("Icon", ""))); if (app_file.icon.is_empty()) { os::println("[taskbar] app file is missing 'Icon' entry, aborting!"); return {}; } os::println("[taskbar] loaded app %s into memory", app_file.name.chars()); TRY(s_app_files.try_append(move(app_file))); return {}; } static Result load_app_files_from_path(StringView path) { os::println("[taskbar] loading app files from %s", path.chars()); auto dir = TRY(os::Directory::open(path)); auto services = TRY(dir->list_names(os::Directory::Filter::ParentAndBase)); sort(services.begin(), services.end(), String::compare); for (const auto& entry : services) TRY(load_application_file({ dir->fd(), entry.view() })); return {}; } Result luna_main(int, char**) { ui::App app; TRY(app.init("/tmp/wsys.sock")); TRY(os::EventLoop::the().register_signal_handler(SIGCHLD, sigchld_handler)); TRY(os::EventLoop::the().register_signal_handler(SIGQUIT, sigquit_handler)); launcher_client = TRY(os::IPC::Client::connect("/tmp/launch.sock", false)); ui::Rect screen = app.screen_rect(); ui::Rect bar = ui::Rect { ui::Point { 0, screen.height - 50 }, screen.width, 50 }; auto window = TRY(ui::Window::create(bar, ui::WindowType::System)); app.set_main_window(window); window->set_background(TASKBAR_COLOR); window->set_special_attributes(ui::UNFOCUSEABLE); ui::HorizontalLayout layout(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No); window->set_main_widget(layout); load_app_files_from_path("/usr/share/applications/"); auto home = TRY(os::FileSystem::home_directory()); StringBuilder sb; TRY(sb.add(home.view())); TRY(sb.add("/.applications/"_sv)); auto local_app_file_dir = TRY(sb.string()); load_app_files_from_path(local_app_file_dir.view()); for (const auto& app_file : s_app_files) { create_widget_group_for_app(layout, app_file.command.view(), app_file.icon.view()); } return app.run(); }