1/*
2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors.
3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com>
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "ServerDecoder.h"
10#include "../Components/Security/Violations.h"
11#include "../Managers/WindowManager.h"
12#include "../Target/Generic/Window.h"
13
14namespace WinServer {
15
16std::unique_ptr<Message> WindowServerDecoder::handle(GreetMessage& msg)
17{
18 return new GreetMessageReply(msg.key(), Connection::the().alloc_connection());
19}
20
21#ifdef TARGET_DESKTOP
22std::unique_ptr<Message> WindowServerDecoder::handle(CreateWindowMessage& msg)
23{
24 auto& wm = WindowManager::the();
25 auto& compositor = Compositor::the();
26 int win_id = wm.next_win_id();
27 auto* window = new Desktop::Window(msg.key(), win_id, msg);
28 window->set_app_title(msg.title().move_string());
29 window->set_icon_path(msg.icon_path().move_string());
30 window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
31 wm.add_window(window);
32 if (window->type() == WindowType::Standard) {
33 // After moving windows, we have to invalidate bounds() to make sure that
34 // the whole window is rendered (coords are changes after move).
35 wm.move_window(window, 8 * win_id, MenuBar::height() + 8 * win_id);
36 compositor.invalidate(window->bounds());
37 }
38
39 wm.notify_window_icon_changed(window->id());
40 wm.notify_window_title_changed(window->id());
41 return new CreateWindowMessageReply(msg.key(), win_id);
42}
43#elif TARGET_MOBILE
44std::unique_ptr<Message> WindowServerDecoder::handle(CreateWindowMessage& msg)
45{
46 auto& wm = WindowManager::the();
47 int win_id = wm.next_win_id();
48 auto* window = new Mobile::Window(msg.key(), win_id, msg);
49 window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
50 window->set_icon_path(msg.icon_path().move_string());
51 window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
52 wm.add_window(window);
53 wm.move_window(window, 0, MenuBar::height());
54 wm.notify_window_icon_changed(window->id());
55 wm.notify_window_title_changed(window->id());
56 return new CreateWindowMessageReply(msg.key(), win_id);
57}
58#endif
59
60std::unique_ptr<Message> WindowServerDecoder::handle(SetBufferMessage& msg)
61{
62 auto* window = WindowManager::the().window(msg.window_id());
63 if (!window) {
64 return nullptr;
65 }
66
67 LG::Size new_size = { msg.bounds().width(), msg.bounds().height() };
68 window->did_size_change(new_size);
69 window->set_buffer(msg.buffer_id(), new_size, LG::PixelBitmapFormat(msg.format()));
70 return nullptr;
71}
72
73std::unique_ptr<Message> WindowServerDecoder::handle(DestroyWindowMessage& msg)
74{
75 auto& wm = WindowManager::the();
76 auto* window = wm.window(msg.window_id());
77 if (!window) {
78 wm.on_window_misbehave(*window, ViolationClass::Ignorable);
79 return new DestroyWindowMessageReply(msg.key(), 1);
80 }
81
82 if (window->connection_id() != msg.key()) {
83 wm.on_window_misbehave(*window, ViolationClass::Serious);
84 return new DestroyWindowMessageReply(msg.key(), 1);
85 }
86 wm.remove_window(window);
87 return new DestroyWindowMessageReply(msg.key(), 0);
88}
89
90std::unique_ptr<Message> WindowServerDecoder::handle(InvalidateMessage& msg)
91{
92 auto& wm = WindowManager::the();
93 auto* window = wm.window(msg.window_id());
94 if (!window) {
95 return nullptr;
96 }
97 auto rect = msg.rect();
98 rect.offset_by(window->content_bounds().origin());
99 rect.intersect(window->content_bounds());
100 Compositor::the().invalidate(rect);
101 return nullptr;
102}
103
104#ifdef TARGET_DESKTOP
105std::unique_ptr<Message> WindowServerDecoder::handle(SetTitleMessage& msg)
106{
107 auto& wm = WindowManager::the();
108 auto* window = wm.window(msg.window_id());
109 if (!window) {
110 return nullptr;
111 }
112 window->set_app_title(msg.title().string());
113
114 auto& compositor = Compositor::the();
115 compositor.invalidate(compositor.menu_bar().bounds());
116 wm.notify_window_title_changed(window->id());
117 return nullptr;
118}
119#elif TARGET_MOBILE
120std::unique_ptr<Message> WindowServerDecoder::handle(SetTitleMessage& msg)
121{
122 return nullptr;
123}
124#endif
125
126std::unique_ptr<Message> WindowServerDecoder::handle(SetBarStyleMessage& msg)
127{
128 auto& wm = WindowManager::the();
129 auto* window = wm.window(msg.window_id());
130 if (!window) {
131 return nullptr;
132 }
133
134 window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
135 return nullptr;
136}
137
138#ifdef TARGET_DESKTOP
139std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateMenuMessage& msg)
140{
141 auto& wm = WindowManager::the();
142 auto* window = wm.window(msg.window_id());
143 if (!window) {
144 return new MenuBarCreateMenuMessageReply(msg.key(), -1, 0);
145 }
146
147 int id = window->menubar_content().size();
148 window->menubar_content().push_back(MenuDir(msg.title().string(), id));
149 window->on_menubar_change();
150 return new MenuBarCreateMenuMessageReply(msg.key(), 0, id);
151}
152
153std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateItemMessage& msg)
154{
155 auto& wm = WindowManager::the();
156 auto* window = wm.window(msg.window_id());
157 if (!window) {
158 return new MenuBarCreateItemMessageReply(msg.key(), -1);
159 }
160
161 auto menu_id = msg.menu_id();
162 if (menu_id == 0 || window->menubar_content().size() <= menu_id) {
163 return new MenuBarCreateItemMessageReply(msg.key(), -2);
164 }
165
166 auto callback = [window, menu_id](int item_id) { LFoundation::EventLoop::the().add(Connection::the(),
167 new SendEvent(new MenuBarActionMessage(window->connection_id(), window->id(), menu_id, item_id))); };
168 window->menubar_content()[menu_id].add_item(PopupItem { msg.item_id(), msg.title().string(), callback });
169 // TODO: Currently we don't redraw popup after a new item was added.
170 return new MenuBarCreateItemMessageReply(msg.key(), 0);
171}
172#elif TARGET_MOBILE
173std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateMenuMessage& msg)
174{
175 return new MenuBarCreateMenuMessageReply(msg.key(), -100, 0);
176}
177
178std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateItemMessage& msg)
179{
180 return new MenuBarCreateItemMessageReply(msg.key(), -100);
181}
182#endif
183
184std::unique_ptr<Message> WindowServerDecoder::handle(PopupShowMenuMessage& msg)
185{
186 auto& wm = WindowManager::the();
187 auto* window = wm.window(msg.window_id());
188
189 if (!window) {
190 return new PopupShowMenuMessageReply(msg.key(), -1, -1);
191 }
192
193 std::vector<std::string> res;
194 for (int i = 0; i < msg.data().vector().size(); i++) {
195 res.push_back(msg.data().vector()[i].move_string());
196 }
197
198 PopupData popup_data;
199 int item_id = 0;
200 int menu_id = 0;
201
202 for (auto& title : res) {
203 auto callback = [window, menu_id](int item_id) { LFoundation::EventLoop::the().add(Connection::the(),
204 new SendEvent(new PopupActionMessage(window->connection_id(), window->id(), menu_id, item_id))); };
205 popup_data.push_back(PopupItem { item_id, title, callback });
206 item_id++;
207 }
208
209 wm.popup().show({ msg.point() }, popup_data);
210 return new PopupShowMenuMessageReply(msg.key(), 0, 0);
211}
212
213std::unique_ptr<Message> WindowServerDecoder::handle(AskBringToFrontMessage& msg)
214{
215 auto& wm = WindowManager::the();
216 auto* window = wm.window(msg.window_id());
217 auto* target_window = wm.window(msg.target_window_id());
218 if (!window || !target_window) {
219 return nullptr;
220 }
221 if (window->type() == WindowType::Homescreen) {
222 // Only dock can ask for that now.
223 wm.ask_to_set_active_window(*target_window);
224 }
225 return nullptr;
226}
227
228} // namespace WinServer