/* * Copyright (C) 2020-2022 The opuntiaOS Project Authors. * + Contributed by Nikita Melekhin * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "ServerDecoder.h" #include "../Components/Security/Violations.h" #include "../Managers/WindowManager.h" #include "../Target/Generic/Window.h" namespace WinServer { std::unique_ptr WindowServerDecoder::handle(GreetMessage& msg) { return new GreetMessageReply(msg.key(), Connection::the().alloc_connection()); } #ifdef TARGET_DESKTOP std::unique_ptr WindowServerDecoder::handle(CreateWindowMessage& msg) { auto& wm = WindowManager::the(); auto& compositor = Compositor::the(); int win_id = wm.next_win_id(); auto* window = new Desktop::Window(msg.key(), win_id, msg); window->set_app_title(msg.title().move_string()); window->set_icon_path(msg.icon_path().move_string()); window->set_style(StatusBarStyle(msg.menubar_style(), msg.color())); wm.add_window(window); if (window->type() == WindowType::Standard) { // After moving windows, we have to invalidate bounds() to make sure that // the whole window is rendered (coords are changes after move). wm.move_window(window, 8 * win_id, MenuBar::height() + 8 * win_id); compositor.invalidate(window->bounds()); } wm.notify_window_icon_changed(window->id()); wm.notify_window_title_changed(window->id()); return new CreateWindowMessageReply(msg.key(), win_id); } #elif TARGET_MOBILE std::unique_ptr WindowServerDecoder::handle(CreateWindowMessage& msg) { auto& wm = WindowManager::the(); int win_id = wm.next_win_id(); auto* window = new Mobile::Window(msg.key(), win_id, msg); window->set_style(StatusBarStyle(msg.menubar_style(), msg.color())); window->set_icon_path(msg.icon_path().move_string()); window->set_style(StatusBarStyle(msg.menubar_style(), msg.color())); wm.add_window(window); wm.move_window(window, 0, MenuBar::height()); wm.notify_window_icon_changed(window->id()); wm.notify_window_title_changed(window->id()); return new CreateWindowMessageReply(msg.key(), win_id); } #endif std::unique_ptr WindowServerDecoder::handle(SetBufferMessage& msg) { auto* window = WindowManager::the().window(msg.window_id()); if (!window) { return nullptr; } LG::Size new_size = { msg.bounds().width(), msg.bounds().height() }; window->did_size_change(new_size); window->set_buffer(msg.buffer_id(), new_size, LG::PixelBitmapFormat(msg.format())); return nullptr; } std::unique_ptr WindowServerDecoder::handle(DestroyWindowMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { wm.on_window_misbehave(*window, ViolationClass::Ignorable); return new DestroyWindowMessageReply(msg.key(), 1); } if (window->connection_id() != msg.key()) { wm.on_window_misbehave(*window, ViolationClass::Serious); return new DestroyWindowMessageReply(msg.key(), 1); } wm.remove_window(window); return new DestroyWindowMessageReply(msg.key(), 0); } std::unique_ptr WindowServerDecoder::handle(InvalidateMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { return nullptr; } auto rect = msg.rect(); rect.offset_by(window->content_bounds().origin()); rect.intersect(window->content_bounds()); Compositor::the().invalidate(rect); return nullptr; } #ifdef TARGET_DESKTOP std::unique_ptr WindowServerDecoder::handle(SetTitleMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { return nullptr; } window->set_app_title(msg.title().string()); auto& compositor = Compositor::the(); compositor.invalidate(compositor.menu_bar().bounds()); wm.notify_window_title_changed(window->id()); return nullptr; } #elif TARGET_MOBILE std::unique_ptr WindowServerDecoder::handle(SetTitleMessage& msg) { return nullptr; } #endif std::unique_ptr WindowServerDecoder::handle(SetBarStyleMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { return nullptr; } window->set_style(StatusBarStyle(msg.menubar_style(), msg.color())); return nullptr; } #ifdef TARGET_DESKTOP std::unique_ptr WindowServerDecoder::handle(MenuBarCreateMenuMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { return new MenuBarCreateMenuMessageReply(msg.key(), -1, 0); } int id = window->menubar_content().size(); window->menubar_content().push_back(MenuDir(msg.title().string(), id)); window->on_menubar_change(); return new MenuBarCreateMenuMessageReply(msg.key(), 0, id); } std::unique_ptr WindowServerDecoder::handle(MenuBarCreateItemMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { return new MenuBarCreateItemMessageReply(msg.key(), -1); } auto menu_id = msg.menu_id(); if (menu_id == 0 || window->menubar_content().size() <= menu_id) { return new MenuBarCreateItemMessageReply(msg.key(), -2); } auto callback = [window, menu_id](int item_id) { LFoundation::EventLoop::the().add(Connection::the(), new SendEvent(new MenuBarActionMessage(window->connection_id(), window->id(), menu_id, item_id))); }; window->menubar_content()[menu_id].add_item(PopupItem { msg.item_id(), msg.title().string(), callback }); // TODO: Currently we don't redraw popup after a new item was added. return new MenuBarCreateItemMessageReply(msg.key(), 0); } #elif TARGET_MOBILE std::unique_ptr WindowServerDecoder::handle(MenuBarCreateMenuMessage& msg) { return new MenuBarCreateMenuMessageReply(msg.key(), -100, 0); } std::unique_ptr WindowServerDecoder::handle(MenuBarCreateItemMessage& msg) { return new MenuBarCreateItemMessageReply(msg.key(), -100); } #endif std::unique_ptr WindowServerDecoder::handle(PopupShowMenuMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); if (!window) { return new PopupShowMenuMessageReply(msg.key(), -1, -1); } std::vector res; for (int i = 0; i < msg.data().vector().size(); i++) { res.push_back(msg.data().vector()[i].move_string()); } PopupData popup_data; int item_id = 0; int menu_id = 0; for (auto& title : res) { auto callback = [window, menu_id](int item_id) { LFoundation::EventLoop::the().add(Connection::the(), new SendEvent(new PopupActionMessage(window->connection_id(), window->id(), menu_id, item_id))); }; popup_data.push_back(PopupItem { item_id, title, callback }); item_id++; } wm.popup().show({ msg.point() }, popup_data); return new PopupShowMenuMessageReply(msg.key(), 0, 0); } std::unique_ptr WindowServerDecoder::handle(AskBringToFrontMessage& msg) { auto& wm = WindowManager::the(); auto* window = wm.window(msg.window_id()); auto* target_window = wm.window(msg.target_window_id()); if (!window || !target_window) { return nullptr; } if (window->type() == WindowType::Homescreen) { // Only dock can ask for that now. wm.ask_to_set_active_window(*target_window); } return nullptr; } } // namespace WinServer