Serenity Operating System
at portability 732 lines 28 kB view raw
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}