Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/Badge.h>
28#include <AK/SharedBuffer.h>
29#include <LibGfx/Bitmap.h>
30#include <LibGfx/SystemTheme.h>
31#include <WindowServer/AppletManager.h>
32#include <WindowServer/ClientConnection.h>
33#include <WindowServer/Clipboard.h>
34#include <WindowServer/Compositor.h>
35#include <WindowServer/EventLoop.h>
36#include <WindowServer/Menu.h>
37#include <WindowServer/MenuBar.h>
38#include <WindowServer/MenuItem.h>
39#include <WindowServer/Screen.h>
40#include <WindowServer/Window.h>
41#include <WindowServer/WindowClientEndpoint.h>
42#include <WindowServer/WindowManager.h>
43#include <WindowServer/WindowSwitcher.h>
44#include <errno.h>
45#include <serenity.h>
46#include <stdio.h>
47#include <unistd.h>
48
49namespace WindowServer {
50
51HashMap<int, NonnullRefPtr<ClientConnection>>* s_connections;
52
53void ClientConnection::for_each_client(Function<void(ClientConnection&)> callback)
54{
55 if (!s_connections)
56 return;
57 for (auto& it : *s_connections) {
58 callback(*it.value);
59 }
60}
61
62ClientConnection* ClientConnection::from_client_id(int client_id)
63{
64 if (!s_connections)
65 return nullptr;
66 auto it = s_connections->find(client_id);
67 if (it == s_connections->end())
68 return nullptr;
69 return (*it).value.ptr();
70}
71
72ClientConnection::ClientConnection(Core::LocalSocket& client_socket, int client_id)
73 : IPC::ClientConnection<WindowServerEndpoint>(*this, client_socket, client_id)
74{
75 if (!s_connections)
76 s_connections = new HashMap<int, NonnullRefPtr<ClientConnection>>;
77 s_connections->set(client_id, *this);
78}
79
80ClientConnection::~ClientConnection()
81{
82 MenuManager::the().close_all_menus_from_client({}, *this);
83 auto windows = move(m_windows);
84 for (auto& window : windows)
85 window.value->detach_client({});
86}
87
88void ClientConnection::die()
89{
90 deferred_invoke([this](auto&) {
91 s_connections->remove(client_id());
92 });
93}
94
95void ClientConnection::notify_about_new_screen_rect(const Gfx::Rect& rect)
96{
97 post_message(Messages::WindowClient::ScreenRectChanged(rect));
98}
99
100void ClientConnection::notify_about_clipboard_contents_changed()
101{
102 post_message(Messages::WindowClient::ClipboardContentsChanged(Clipboard::the().data_type()));
103}
104
105OwnPtr<Messages::WindowServer::CreateMenubarResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenubar&)
106{
107 int menubar_id = m_next_menubar_id++;
108 auto menubar = make<MenuBar>(*this, menubar_id);
109 m_menubars.set(menubar_id, move(menubar));
110 return make<Messages::WindowServer::CreateMenubarResponse>(menubar_id);
111}
112
113OwnPtr<Messages::WindowServer::DestroyMenubarResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenubar& message)
114{
115 int menubar_id = message.menubar_id();
116 auto it = m_menubars.find(menubar_id);
117 if (it == m_menubars.end()) {
118 did_misbehave("DestroyMenubar: Bad menubar ID");
119 return nullptr;
120 }
121 auto& menubar = *(*it).value;
122 MenuManager::the().close_menubar(menubar);
123 m_menubars.remove(it);
124 return make<Messages::WindowServer::DestroyMenubarResponse>();
125}
126
127OwnPtr<Messages::WindowServer::CreateMenuResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenu& message)
128{
129 int menu_id = m_next_menu_id++;
130 auto menu = Menu::construct(this, menu_id, message.menu_title());
131 m_menus.set(menu_id, move(menu));
132 return make<Messages::WindowServer::CreateMenuResponse>(menu_id);
133}
134
135OwnPtr<Messages::WindowServer::DestroyMenuResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenu& message)
136{
137 int menu_id = message.menu_id();
138 auto it = m_menus.find(menu_id);
139 if (it == m_menus.end()) {
140 did_misbehave("DestroyMenu: Bad menu ID");
141 return nullptr;
142 }
143 auto& menu = *(*it).value;
144 menu.close();
145 m_menus.remove(it);
146 remove_child(menu);
147 return make<Messages::WindowServer::DestroyMenuResponse>();
148}
149
150OwnPtr<Messages::WindowServer::SetApplicationMenubarResponse> ClientConnection::handle(const Messages::WindowServer::SetApplicationMenubar& message)
151{
152 int menubar_id = message.menubar_id();
153 auto it = m_menubars.find(menubar_id);
154 if (it == m_menubars.end()) {
155 did_misbehave("SetApplicationMenubar: Bad menubar ID");
156 return nullptr;
157 }
158 auto& menubar = *(*it).value;
159 m_app_menubar = menubar.make_weak_ptr();
160 WindowManager::the().notify_client_changed_app_menubar(*this);
161 return make<Messages::WindowServer::SetApplicationMenubarResponse>();
162}
163
164OwnPtr<Messages::WindowServer::AddMenuToMenubarResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuToMenubar& message)
165{
166 int menubar_id = message.menubar_id();
167 int menu_id = message.menu_id();
168 auto it = m_menubars.find(menubar_id);
169 auto jt = m_menus.find(menu_id);
170 if (it == m_menubars.end()) {
171 did_misbehave("AddMenuToMenubar: Bad menubar ID");
172 return nullptr;
173 }
174 if (jt == m_menus.end()) {
175 did_misbehave("AddMenuToMenubar: Bad menu ID");
176 return nullptr;
177 }
178 auto& menubar = *(*it).value;
179 auto& menu = *(*jt).value;
180 menubar.add_menu(menu);
181 return make<Messages::WindowServer::AddMenuToMenubarResponse>();
182}
183
184OwnPtr<Messages::WindowServer::AddMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuItem& message)
185{
186 int menu_id = message.menu_id();
187 unsigned identifier = message.identifier();
188 auto it = m_menus.find(menu_id);
189 if (it == m_menus.end()) {
190 dbg() << "AddMenuItem: Bad menu ID: " << menu_id;
191 return nullptr;
192 }
193 auto& menu = *(*it).value;
194 auto menu_item = make<MenuItem>(menu, identifier, message.text(), message.shortcut(), message.enabled(), message.checkable(), message.checked());
195 if (message.icon_buffer_id() != -1) {
196 auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(message.icon_buffer_id());
197 if (!icon_buffer)
198 return nullptr;
199 // FIXME: Verify that the icon buffer can accomodate a 16x16 bitmap view.
200 auto shared_icon = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, icon_buffer.release_nonnull(), { 16, 16 });
201 menu_item->set_icon(shared_icon);
202 }
203 menu_item->set_submenu_id(message.submenu_id());
204 menu_item->set_exclusive(message.exclusive());
205 menu.add_item(move(menu_item));
206 return make<Messages::WindowServer::AddMenuItemResponse>();
207}
208
209OwnPtr<Messages::WindowServer::PopupMenuResponse> ClientConnection::handle(const Messages::WindowServer::PopupMenu& message)
210{
211 int menu_id = message.menu_id();
212 auto position = message.screen_position();
213 auto it = m_menus.find(menu_id);
214 if (it == m_menus.end()) {
215 did_misbehave("PopupMenu: Bad menu ID");
216 return nullptr;
217 }
218 auto& menu = *(*it).value;
219 menu.popup(position);
220 return make<Messages::WindowServer::PopupMenuResponse>();
221}
222
223OwnPtr<Messages::WindowServer::DismissMenuResponse> ClientConnection::handle(const Messages::WindowServer::DismissMenu& message)
224{
225 int menu_id = message.menu_id();
226 auto it = m_menus.find(menu_id);
227 if (it == m_menus.end()) {
228 did_misbehave("DismissMenu: Bad menu ID");
229 return nullptr;
230 }
231 auto& menu = *(*it).value;
232 menu.close();
233 return make<Messages::WindowServer::DismissMenuResponse>();
234}
235
236OwnPtr<Messages::WindowServer::UpdateMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::UpdateMenuItem& message)
237{
238 int menu_id = message.menu_id();
239 auto it = m_menus.find(menu_id);
240 if (it == m_menus.end()) {
241 did_misbehave("UpdateMenuItem: Bad menu ID");
242 return nullptr;
243 }
244 auto& menu = *(*it).value;
245 auto* menu_item = menu.item_with_identifier(message.identifier());
246 if (!menu_item) {
247 did_misbehave("UpdateMenuItem: Bad menu item identifier");
248 return nullptr;
249 }
250 menu_item->set_text(message.text());
251 menu_item->set_shortcut_text(message.shortcut());
252 menu_item->set_enabled(message.enabled());
253 menu_item->set_checkable(message.checkable());
254 if (message.checkable())
255 menu_item->set_checked(message.checked());
256 return make<Messages::WindowServer::UpdateMenuItemResponse>();
257}
258
259OwnPtr<Messages::WindowServer::AddMenuSeparatorResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuSeparator& message)
260{
261 int menu_id = message.menu_id();
262 auto it = m_menus.find(menu_id);
263 if (it == m_menus.end()) {
264 did_misbehave("AddMenuSeparator: Bad menu ID");
265 return nullptr;
266 }
267 auto& menu = *(*it).value;
268 menu.add_item(make<MenuItem>(menu, MenuItem::Separator));
269 return make<Messages::WindowServer::AddMenuSeparatorResponse>();
270}
271
272OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> ClientConnection::handle(const Messages::WindowServer::MoveWindowToFront& message)
273{
274 auto it = m_windows.find(message.window_id());
275 if (it == m_windows.end()) {
276 did_misbehave("MoveWindowToFront: Bad window ID");
277 return nullptr;
278 }
279 WindowManager::the().move_to_front_and_make_active(*(*it).value);
280 return make<Messages::WindowServer::MoveWindowToFrontResponse>();
281}
282
283OwnPtr<Messages::WindowServer::SetFullscreenResponse> ClientConnection::handle(const Messages::WindowServer::SetFullscreen& message)
284{
285 auto it = m_windows.find(message.window_id());
286 if (it == m_windows.end()) {
287 did_misbehave("SetFullscreen: Bad window ID");
288 return nullptr;
289 }
290 it->value->set_fullscreen(message.fullscreen());
291 return make<Messages::WindowServer::SetFullscreenResponse>();
292}
293
294OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOpacity& message)
295{
296 auto it = m_windows.find(message.window_id());
297 if (it == m_windows.end()) {
298 did_misbehave("SetWindowOpacity: Bad window ID");
299 return nullptr;
300 }
301 it->value->set_opacity(message.opacity());
302 return make<Messages::WindowServer::SetWindowOpacityResponse>();
303}
304
305void ClientConnection::handle(const Messages::WindowServer::AsyncSetWallpaper& message)
306{
307 Compositor::the().set_wallpaper(message.path(), [&](bool success) {
308 post_message(Messages::WindowClient::AsyncSetWallpaperFinished(success));
309 });
310}
311
312OwnPtr<Messages::WindowServer::GetWallpaperResponse> ClientConnection::handle(const Messages::WindowServer::GetWallpaper&)
313{
314 return make<Messages::WindowServer::GetWallpaperResponse>(Compositor::the().wallpaper_path());
315}
316
317OwnPtr<Messages::WindowServer::SetResolutionResponse> ClientConnection::handle(const Messages::WindowServer::SetResolution& message)
318{
319 WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height());
320 return make<Messages::WindowServer::SetResolutionResponse>();
321}
322
323OwnPtr<Messages::WindowServer::SetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowTitle& message)
324{
325 auto it = m_windows.find(message.window_id());
326 if (it == m_windows.end()) {
327 did_misbehave("SetWindowTitle: Bad window ID");
328 return nullptr;
329 }
330 it->value->set_title(message.title());
331 return make<Messages::WindowServer::SetWindowTitleResponse>();
332}
333
334OwnPtr<Messages::WindowServer::GetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowTitle& message)
335{
336 auto it = m_windows.find(message.window_id());
337 if (it == m_windows.end()) {
338 did_misbehave("GetWindowTitle: Bad window ID");
339 return nullptr;
340 }
341 return make<Messages::WindowServer::GetWindowTitleResponse>(it->value->title());
342}
343
344OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowIconBitmap& message)
345{
346 auto it = m_windows.find(message.window_id());
347 if (it == m_windows.end()) {
348 did_misbehave("SetWindowIconBitmap: Bad window ID");
349 return nullptr;
350 }
351 auto& window = *(*it).value;
352
353 auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(message.icon_buffer_id());
354
355 if (!icon_buffer) {
356 window.set_default_icon();
357 } else {
358 window.set_icon(Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *icon_buffer, message.icon_size()));
359 }
360
361 window.frame().invalidate_title_bar();
362 WindowManager::the().tell_wm_listeners_window_icon_changed(window);
363 return make<Messages::WindowServer::SetWindowIconBitmapResponse>();
364}
365
366OwnPtr<Messages::WindowServer::SetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowRect& message)
367{
368 int window_id = message.window_id();
369 auto it = m_windows.find(window_id);
370 if (it == m_windows.end()) {
371 did_misbehave("SetWindowRect: Bad window ID");
372 return nullptr;
373 }
374 auto& window = *(*it).value;
375 if (window.is_fullscreen()) {
376 dbg() << "ClientConnection: Ignoring SetWindowRect request for fullscreen window";
377 return nullptr;
378 }
379 window.set_rect(message.rect());
380 window.request_update(message.rect());
381 return make<Messages::WindowServer::SetWindowRectResponse>();
382}
383
384OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRect& message)
385{
386 int window_id = message.window_id();
387 auto it = m_windows.find(window_id);
388 if (it == m_windows.end()) {
389 did_misbehave("GetWindowRect: Bad window ID");
390 return nullptr;
391 }
392 return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect());
393}
394
395OwnPtr<Messages::WindowServer::SetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::SetClipboardContents& message)
396{
397 auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(message.shared_buffer_id());
398 if (!shared_buffer) {
399 did_misbehave("SetClipboardContents: Bad shared buffer ID");
400 return nullptr;
401 }
402 Clipboard::the().set_data(*shared_buffer, message.content_size(), message.content_type());
403 return make<Messages::WindowServer::SetClipboardContentsResponse>();
404}
405
406OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::GetClipboardContents&)
407{
408 auto& clipboard = Clipboard::the();
409
410 i32 shared_buffer_id = -1;
411 if (clipboard.size()) {
412 // FIXME: Optimize case where an app is copy/pasting within itself.
413 // We can just reuse the SharedBuffer then, since it will have the same peer PID.
414 // It would be even nicer if a SharedBuffer could have an arbitrary number of clients..
415 RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(clipboard.size());
416 ASSERT(shared_buffer);
417 memcpy(shared_buffer->data(), clipboard.data(), clipboard.size());
418 shared_buffer->seal();
419 shared_buffer->share_with(client_pid());
420 shared_buffer_id = shared_buffer->shared_buffer_id();
421
422 // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them.
423 // After we respond to GetClipboardContents, we have to wait for the client to ref the buffer on his side.
424 m_last_sent_clipboard_content = move(shared_buffer);
425 }
426 return make<Messages::WindowServer::GetClipboardContentsResponse>(shared_buffer_id, clipboard.size(), clipboard.data_type());
427}
428
429OwnPtr<Messages::WindowServer::CreateWindowResponse> ClientConnection::handle(const Messages::WindowServer::CreateWindow& message)
430{
431 int window_id = m_next_window_id++;
432 auto window = Window::construct(*this, (WindowType)message.type(), window_id, message.modal(), message.minimizable(), message.resizable(), message.fullscreen());
433 window->set_has_alpha_channel(message.has_alpha_channel());
434 window->set_title(message.title());
435 if (!message.fullscreen())
436 window->set_rect(message.rect());
437 window->set_show_titlebar(message.show_titlebar());
438 window->set_opacity(message.opacity());
439 window->set_size_increment(message.size_increment());
440 window->set_base_size(message.base_size());
441 window->invalidate();
442 if (window->type() == WindowType::MenuApplet)
443 AppletManager::the().add_applet(*window);
444 m_windows.set(window_id, move(window));
445 return make<Messages::WindowServer::CreateWindowResponse>(window_id);
446}
447
448OwnPtr<Messages::WindowServer::DestroyWindowResponse> ClientConnection::handle(const Messages::WindowServer::DestroyWindow& message)
449{
450 auto it = m_windows.find(message.window_id());
451 if (it == m_windows.end()) {
452 did_misbehave("DestroyWindow: Bad window ID");
453 return nullptr;
454 }
455 auto& window = *(*it).value;
456
457 if (window.type() == WindowType::MenuApplet)
458 AppletManager::the().remove_applet(window);
459
460 WindowManager::the().invalidate(window);
461 remove_child(window);
462 ASSERT(it->value.ptr() == &window);
463 m_windows.remove(message.window_id());
464
465 return make<Messages::WindowServer::DestroyWindowResponse>();
466}
467
468void ClientConnection::post_paint_message(Window& window, bool ignore_occlusion)
469{
470 auto rect_set = window.take_pending_paint_rects();
471 if (window.is_minimized() || (!ignore_occlusion && window.is_occluded()))
472 return;
473
474 post_message(Messages::WindowClient::Paint(window.window_id(), window.size(), rect_set.rects()));
475}
476
477void ClientConnection::handle(const Messages::WindowServer::InvalidateRect& message)
478{
479 auto it = m_windows.find(message.window_id());
480 if (it == m_windows.end()) {
481 did_misbehave("InvalidateRect: Bad window ID");
482 return;
483 }
484 auto& window = *(*it).value;
485 for (size_t i = 0; i < message.rects().size(); ++i)
486 window.request_update(message.rects()[i].intersected({ {}, window.size() }), message.ignore_occlusion());
487}
488
489void ClientConnection::handle(const Messages::WindowServer::DidFinishPainting& message)
490{
491 int window_id = message.window_id();
492 auto it = m_windows.find(window_id);
493 if (it == m_windows.end()) {
494 did_misbehave("DidFinishPainting: Bad window ID");
495 return;
496 }
497 auto& window = *(*it).value;
498 for (auto& rect : message.rects())
499 WindowManager::the().invalidate(window, rect);
500
501 WindowSwitcher::the().refresh_if_needed();
502}
503
504OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBackingStore& message)
505{
506 int window_id = message.window_id();
507 auto it = m_windows.find(window_id);
508 if (it == m_windows.end()) {
509 did_misbehave("SetWindowBackingStore: Bad window ID");
510 return nullptr;
511 }
512 auto& window = *(*it).value;
513 if (window.last_backing_store() && window.last_backing_store()->shared_buffer_id() == message.shared_buffer_id()) {
514 window.swap_backing_stores();
515 } else {
516 auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(message.shared_buffer_id());
517 if (!shared_buffer)
518 return make<Messages::WindowServer::SetWindowBackingStoreResponse>();
519 auto backing_store = Gfx::Bitmap::create_with_shared_buffer(
520 message.has_alpha_channel() ? Gfx::BitmapFormat::RGBA32 : Gfx::BitmapFormat::RGB32,
521 *shared_buffer,
522 message.size());
523 window.set_backing_store(move(backing_store));
524 }
525
526 if (message.flush_immediately())
527 window.invalidate();
528
529 return make<Messages::WindowServer::SetWindowBackingStoreResponse>();
530}
531
532OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> ClientConnection::handle(const Messages::WindowServer::SetGlobalCursorTracking& message)
533{
534 int window_id = message.window_id();
535 auto it = m_windows.find(window_id);
536 if (it == m_windows.end()) {
537 did_misbehave("SetGlobalCursorTracking: Bad window ID");
538 return nullptr;
539 }
540 it->value->set_global_cursor_tracking_enabled(message.enabled());
541 return make<Messages::WindowServer::SetGlobalCursorTrackingResponse>();
542}
543
544OwnPtr<Messages::WindowServer::SetWindowOverrideCursorResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOverrideCursor& message)
545{
546 auto it = m_windows.find(message.window_id());
547 if (it == m_windows.end()) {
548 did_misbehave("SetWindowOverrideCursor: Bad window ID");
549 return nullptr;
550 }
551 auto& window = *(*it).value;
552 window.set_override_cursor(Cursor::create((StandardCursor)message.cursor_type()));
553 return make<Messages::WindowServer::SetWindowOverrideCursorResponse>();
554}
555
556OwnPtr<Messages::WindowServer::SetWindowHasAlphaChannelResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowHasAlphaChannel& message)
557{
558 auto it = m_windows.find(message.window_id());
559 if (it == m_windows.end()) {
560 did_misbehave("SetWindowHasAlphaChannel: Bad window ID");
561 return nullptr;
562 }
563 it->value->set_has_alpha_channel(message.has_alpha_channel());
564 return make<Messages::WindowServer::SetWindowHasAlphaChannelResponse>();
565}
566
567void ClientConnection::handle(const Messages::WindowServer::WM_SetActiveWindow& message)
568{
569 auto* client = ClientConnection::from_client_id(message.client_id());
570 if (!client) {
571 did_misbehave("WM_SetActiveWindow: Bad client ID");
572 return;
573 }
574 auto it = client->m_windows.find(message.window_id());
575 if (it == client->m_windows.end()) {
576 did_misbehave("WM_SetActiveWindow: Bad window ID");
577 return;
578 }
579 auto& window = *(*it).value;
580 window.set_minimized(false);
581 WindowManager::the().move_to_front_and_make_active(window);
582}
583
584void ClientConnection::handle(const Messages::WindowServer::WM_PopupWindowMenu& message)
585{
586 auto* client = ClientConnection::from_client_id(message.client_id());
587 if (!client) {
588 did_misbehave("WM_PopupWindowMenu: Bad client ID");
589 return;
590 }
591 auto it = client->m_windows.find(message.window_id());
592 if (it == client->m_windows.end()) {
593 did_misbehave("WM_PopupWindowMenu: Bad window ID");
594 return;
595 }
596 auto& window = *(*it).value;
597 window.popup_window_menu(message.screen_position());
598}
599
600void ClientConnection::handle(const Messages::WindowServer::WM_StartWindowResize& request)
601{
602 auto* client = ClientConnection::from_client_id(request.client_id());
603 if (!client) {
604 did_misbehave("WM_StartWindowResize: Bad client ID");
605 return;
606 }
607 auto it = client->m_windows.find(request.window_id());
608 if (it == client->m_windows.end()) {
609 did_misbehave("WM_StartWindowResize: Bad window ID");
610 return;
611 }
612 auto& window = *(*it).value;
613 // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button.
614 // Maybe the client should be allowed to specify what initiated this request?
615 WindowManager::the().start_window_resize(window, Screen::the().cursor_location(), MouseButton::Left);
616}
617
618void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowMinimized& message)
619{
620 auto* client = ClientConnection::from_client_id(message.client_id());
621 if (!client) {
622 did_misbehave("WM_SetWindowMinimized: Bad client ID");
623 return;
624 }
625 auto it = client->m_windows.find(message.window_id());
626 if (it == client->m_windows.end()) {
627 did_misbehave("WM_SetWindowMinimized: Bad window ID");
628 return;
629 }
630 auto& window = *(*it).value;
631 window.set_minimized(message.minimized());
632}
633
634OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&)
635{
636 return make<Messages::WindowServer::GreetResponse>(client_id(), Screen::the().rect(), Gfx::current_system_theme_buffer_id());
637}
638
639bool ClientConnection::is_showing_modal_window() const
640{
641 for (auto& it : m_windows) {
642 auto& window = *it.value;
643 if (window.is_visible() && window.is_modal())
644 return true;
645 }
646 return false;
647}
648
649void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowTaskbarRect& message)
650{
651 auto* client = ClientConnection::from_client_id(message.client_id());
652 if (!client) {
653 did_misbehave("WM_SetWindowTaskbarRect: Bad client ID");
654 return;
655 }
656 auto it = client->m_windows.find(message.window_id());
657 if (it == client->m_windows.end()) {
658 did_misbehave("WM_SetWindowTaskbarRect: Bad window ID");
659 return;
660 }
661 auto& window = *(*it).value;
662 window.set_taskbar_rect(message.rect());
663}
664
665OwnPtr<Messages::WindowServer::StartDragResponse> ClientConnection::handle(const Messages::WindowServer::StartDrag& message)
666{
667 auto& wm = WindowManager::the();
668 if (wm.dnd_client())
669 return make<Messages::WindowServer::StartDragResponse>(false);
670
671 RefPtr<Gfx::Bitmap> bitmap;
672 if (message.bitmap_id() != -1) {
673 auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(message.bitmap_id());
674 ssize_t size_in_bytes = message.bitmap_size().area() * sizeof(Gfx::RGBA32);
675 if (size_in_bytes > shared_buffer->size()) {
676 did_misbehave("SetAppletBackingStore: Shared buffer is too small for applet size");
677 return nullptr;
678 }
679 bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *shared_buffer, message.bitmap_size());
680 }
681
682 wm.start_dnd_drag(*this, message.text(), bitmap, message.data_type(), message.data());
683 return make<Messages::WindowServer::StartDragResponse>(true);
684}
685
686OwnPtr<Messages::WindowServer::SetSystemMenuResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemMenu& message)
687{
688 auto it = m_menus.find(message.menu_id());
689 if (it == m_menus.end()) {
690 did_misbehave("SetSystemMenu called with invalid menu ID");
691 return nullptr;
692 }
693
694 auto& menu = it->value;
695 MenuManager::the().set_system_menu(menu);
696 return make<Messages::WindowServer::SetSystemMenuResponse>();
697}
698
699OwnPtr<Messages::WindowServer::SetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemTheme& message)
700{
701 bool success = WindowManager::the().update_theme(message.theme_path(), message.theme_name());
702 return make<Messages::WindowServer::SetSystemThemeResponse>(success);
703}
704
705void ClientConnection::boost()
706{
707 if (set_process_boost(client_pid(), 10) < 0)
708 perror("boost: set_process_boost");
709}
710
711void ClientConnection::deboost()
712{
713 if (set_process_boost(client_pid(), 0) < 0)
714 perror("deboost: set_process_boost");
715}
716
717OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement& message)
718{
719 auto it = m_windows.find(message.window_id());
720 if (it == m_windows.end()) {
721 did_misbehave("SetWindowBaseSizeAndSizeIncrementResponse: Bad window ID");
722 return nullptr;
723 }
724
725 auto& window = *it->value;
726 window.set_base_size(message.base_size());
727 window.set_size_increment(message.size_increment());
728
729 return make<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse>();
730}
731
732}