Serenity Operating System
at hosted 768 lines 30 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 if (window.value->type() == WindowType::MenuApplet) 87 AppletManager::the().remove_applet(window.value); 88 } 89} 90 91void ClientConnection::die() 92{ 93 deferred_invoke([this](auto&) { 94 s_connections->remove(client_id()); 95 }); 96} 97 98void ClientConnection::notify_about_new_screen_rect(const Gfx::Rect& rect) 99{ 100 post_message(Messages::WindowClient::ScreenRectChanged(rect)); 101} 102 103void ClientConnection::notify_about_clipboard_contents_changed() 104{ 105 post_message(Messages::WindowClient::ClipboardContentsChanged(Clipboard::the().data_type())); 106} 107 108OwnPtr<Messages::WindowServer::CreateMenubarResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenubar&) 109{ 110 int menubar_id = m_next_menubar_id++; 111 auto menubar = make<MenuBar>(*this, menubar_id); 112 m_menubars.set(menubar_id, move(menubar)); 113 return make<Messages::WindowServer::CreateMenubarResponse>(menubar_id); 114} 115 116OwnPtr<Messages::WindowServer::DestroyMenubarResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenubar& message) 117{ 118 int menubar_id = message.menubar_id(); 119 auto it = m_menubars.find(menubar_id); 120 if (it == m_menubars.end()) { 121 did_misbehave("DestroyMenubar: Bad menubar ID"); 122 return nullptr; 123 } 124 auto& menubar = *(*it).value; 125 MenuManager::the().close_menubar(menubar); 126 m_menubars.remove(it); 127 return make<Messages::WindowServer::DestroyMenubarResponse>(); 128} 129 130OwnPtr<Messages::WindowServer::CreateMenuResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenu& message) 131{ 132 int menu_id = m_next_menu_id++; 133 auto menu = Menu::construct(this, menu_id, message.menu_title()); 134 m_menus.set(menu_id, move(menu)); 135 return make<Messages::WindowServer::CreateMenuResponse>(menu_id); 136} 137 138OwnPtr<Messages::WindowServer::DestroyMenuResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenu& message) 139{ 140 int menu_id = message.menu_id(); 141 auto it = m_menus.find(menu_id); 142 if (it == m_menus.end()) { 143 did_misbehave("DestroyMenu: Bad menu ID"); 144 return nullptr; 145 } 146 auto& menu = *(*it).value; 147 menu.close(); 148 m_menus.remove(it); 149 remove_child(menu); 150 return make<Messages::WindowServer::DestroyMenuResponse>(); 151} 152 153OwnPtr<Messages::WindowServer::SetApplicationMenubarResponse> ClientConnection::handle(const Messages::WindowServer::SetApplicationMenubar& message) 154{ 155 int menubar_id = message.menubar_id(); 156 auto it = m_menubars.find(menubar_id); 157 if (it == m_menubars.end()) { 158 did_misbehave("SetApplicationMenubar: Bad menubar ID"); 159 return nullptr; 160 } 161 auto& menubar = *(*it).value; 162 m_app_menubar = menubar.make_weak_ptr(); 163 WindowManager::the().notify_client_changed_app_menubar(*this); 164 return make<Messages::WindowServer::SetApplicationMenubarResponse>(); 165} 166 167OwnPtr<Messages::WindowServer::AddMenuToMenubarResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuToMenubar& message) 168{ 169 int menubar_id = message.menubar_id(); 170 int menu_id = message.menu_id(); 171 auto it = m_menubars.find(menubar_id); 172 auto jt = m_menus.find(menu_id); 173 if (it == m_menubars.end()) { 174 did_misbehave("AddMenuToMenubar: Bad menubar ID"); 175 return nullptr; 176 } 177 if (jt == m_menus.end()) { 178 did_misbehave("AddMenuToMenubar: Bad menu ID"); 179 return nullptr; 180 } 181 auto& menubar = *(*it).value; 182 auto& menu = *(*jt).value; 183 menubar.add_menu(menu); 184 return make<Messages::WindowServer::AddMenuToMenubarResponse>(); 185} 186 187OwnPtr<Messages::WindowServer::AddMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuItem& message) 188{ 189 int menu_id = message.menu_id(); 190 unsigned identifier = message.identifier(); 191 auto it = m_menus.find(menu_id); 192 if (it == m_menus.end()) { 193 dbg() << "AddMenuItem: Bad menu ID: " << menu_id; 194 return nullptr; 195 } 196 auto& menu = *(*it).value; 197 auto menu_item = make<MenuItem>(menu, identifier, message.text(), message.shortcut(), message.enabled(), message.checkable(), message.checked()); 198 if (message.icon_buffer_id() != -1) { 199 auto icon_buffer = SharedBuffer::create_from_shbuf_id(message.icon_buffer_id()); 200 if (!icon_buffer) 201 return nullptr; 202 // FIXME: Verify that the icon buffer can accomodate a 16x16 bitmap view. 203 auto shared_icon = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, icon_buffer.release_nonnull(), { 16, 16 }); 204 menu_item->set_icon(shared_icon); 205 } 206 menu_item->set_submenu_id(message.submenu_id()); 207 menu_item->set_exclusive(message.exclusive()); 208 menu.add_item(move(menu_item)); 209 return make<Messages::WindowServer::AddMenuItemResponse>(); 210} 211 212OwnPtr<Messages::WindowServer::PopupMenuResponse> ClientConnection::handle(const Messages::WindowServer::PopupMenu& message) 213{ 214 int menu_id = message.menu_id(); 215 auto position = message.screen_position(); 216 auto it = m_menus.find(menu_id); 217 if (it == m_menus.end()) { 218 did_misbehave("PopupMenu: Bad menu ID"); 219 return nullptr; 220 } 221 auto& menu = *(*it).value; 222 menu.popup(position); 223 return make<Messages::WindowServer::PopupMenuResponse>(); 224} 225 226OwnPtr<Messages::WindowServer::DismissMenuResponse> ClientConnection::handle(const Messages::WindowServer::DismissMenu& message) 227{ 228 int menu_id = message.menu_id(); 229 auto it = m_menus.find(menu_id); 230 if (it == m_menus.end()) { 231 did_misbehave("DismissMenu: Bad menu ID"); 232 return nullptr; 233 } 234 auto& menu = *(*it).value; 235 menu.close(); 236 return make<Messages::WindowServer::DismissMenuResponse>(); 237} 238 239OwnPtr<Messages::WindowServer::UpdateMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::UpdateMenuItem& message) 240{ 241 int menu_id = message.menu_id(); 242 auto it = m_menus.find(menu_id); 243 if (it == m_menus.end()) { 244 did_misbehave("UpdateMenuItem: Bad menu ID"); 245 return nullptr; 246 } 247 auto& menu = *(*it).value; 248 auto* menu_item = menu.item_with_identifier(message.identifier()); 249 if (!menu_item) { 250 did_misbehave("UpdateMenuItem: Bad menu item identifier"); 251 return nullptr; 252 } 253 menu_item->set_text(message.text()); 254 menu_item->set_shortcut_text(message.shortcut()); 255 menu_item->set_enabled(message.enabled()); 256 menu_item->set_checkable(message.checkable()); 257 if (message.checkable()) 258 menu_item->set_checked(message.checked()); 259 return make<Messages::WindowServer::UpdateMenuItemResponse>(); 260} 261 262OwnPtr<Messages::WindowServer::AddMenuSeparatorResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuSeparator& message) 263{ 264 int menu_id = message.menu_id(); 265 auto it = m_menus.find(menu_id); 266 if (it == m_menus.end()) { 267 did_misbehave("AddMenuSeparator: Bad menu ID"); 268 return nullptr; 269 } 270 auto& menu = *(*it).value; 271 menu.add_item(make<MenuItem>(menu, MenuItem::Separator)); 272 return make<Messages::WindowServer::AddMenuSeparatorResponse>(); 273} 274 275OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> ClientConnection::handle(const Messages::WindowServer::MoveWindowToFront& message) 276{ 277 auto it = m_windows.find(message.window_id()); 278 if (it == m_windows.end()) { 279 did_misbehave("MoveWindowToFront: Bad window ID"); 280 return nullptr; 281 } 282 WindowManager::the().move_to_front_and_make_active(*(*it).value); 283 return make<Messages::WindowServer::MoveWindowToFrontResponse>(); 284} 285 286OwnPtr<Messages::WindowServer::SetFullscreenResponse> ClientConnection::handle(const Messages::WindowServer::SetFullscreen& message) 287{ 288 auto it = m_windows.find(message.window_id()); 289 if (it == m_windows.end()) { 290 did_misbehave("SetFullscreen: Bad window ID"); 291 return nullptr; 292 } 293 it->value->set_fullscreen(message.fullscreen()); 294 return make<Messages::WindowServer::SetFullscreenResponse>(); 295} 296 297OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOpacity& message) 298{ 299 auto it = m_windows.find(message.window_id()); 300 if (it == m_windows.end()) { 301 did_misbehave("SetWindowOpacity: Bad window ID"); 302 return nullptr; 303 } 304 it->value->set_opacity(message.opacity()); 305 return make<Messages::WindowServer::SetWindowOpacityResponse>(); 306} 307 308void ClientConnection::handle(const Messages::WindowServer::AsyncSetWallpaper& message) 309{ 310 Compositor::the().set_wallpaper(message.path(), [&](bool success) { 311 post_message(Messages::WindowClient::AsyncSetWallpaperFinished(success)); 312 }); 313} 314 315OwnPtr<Messages::WindowServer::SetBackgroundColorResponse> ClientConnection::handle(const Messages::WindowServer::SetBackgroundColor& message) 316{ 317 Compositor::the().set_backgound_color(message.background_color()); 318 return make<Messages::WindowServer::SetBackgroundColorResponse>(); 319} 320 321OwnPtr<Messages::WindowServer::SetWallpaperModeResponse> ClientConnection::handle(const Messages::WindowServer::SetWallpaperMode& message) 322{ 323 Compositor::the().set_wallpaper_mode(message.mode()); 324 return make<Messages::WindowServer::SetWallpaperModeResponse>(); 325} 326 327OwnPtr<Messages::WindowServer::GetWallpaperResponse> ClientConnection::handle(const Messages::WindowServer::GetWallpaper&) 328{ 329 return make<Messages::WindowServer::GetWallpaperResponse>(Compositor::the().wallpaper_path()); 330} 331 332OwnPtr<Messages::WindowServer::SetResolutionResponse> ClientConnection::handle(const Messages::WindowServer::SetResolution& message) 333{ 334 return make<Messages::WindowServer::SetResolutionResponse>(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height()), WindowManager::the().resolution()); 335} 336 337OwnPtr<Messages::WindowServer::SetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowTitle& message) 338{ 339 auto it = m_windows.find(message.window_id()); 340 if (it == m_windows.end()) { 341 did_misbehave("SetWindowTitle: Bad window ID"); 342 return nullptr; 343 } 344 it->value->set_title(message.title()); 345 return make<Messages::WindowServer::SetWindowTitleResponse>(); 346} 347 348OwnPtr<Messages::WindowServer::GetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowTitle& message) 349{ 350 auto it = m_windows.find(message.window_id()); 351 if (it == m_windows.end()) { 352 did_misbehave("GetWindowTitle: Bad window ID"); 353 return nullptr; 354 } 355 return make<Messages::WindowServer::GetWindowTitleResponse>(it->value->title()); 356} 357 358OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowIconBitmap& message) 359{ 360 auto it = m_windows.find(message.window_id()); 361 if (it == m_windows.end()) { 362 did_misbehave("SetWindowIconBitmap: Bad window ID"); 363 return nullptr; 364 } 365 auto& window = *(*it).value; 366 367 if (message.icon().is_valid()) { 368 window.set_icon(*message.icon().bitmap()); 369 } else { 370 window.set_default_icon(); 371 } 372 373 window.frame().invalidate_title_bar(); 374 WindowManager::the().tell_wm_listeners_window_icon_changed(window); 375 return make<Messages::WindowServer::SetWindowIconBitmapResponse>(); 376} 377 378OwnPtr<Messages::WindowServer::SetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowRect& message) 379{ 380 int window_id = message.window_id(); 381 auto it = m_windows.find(window_id); 382 if (it == m_windows.end()) { 383 did_misbehave("SetWindowRect: Bad window ID"); 384 return nullptr; 385 } 386 auto& window = *(*it).value; 387 if (window.is_fullscreen()) { 388 dbg() << "ClientConnection: Ignoring SetWindowRect request for fullscreen window"; 389 return nullptr; 390 } 391 window.set_rect(message.rect()); 392 window.request_update(message.rect()); 393 return make<Messages::WindowServer::SetWindowRectResponse>(); 394} 395 396OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRect& message) 397{ 398 int window_id = message.window_id(); 399 auto it = m_windows.find(window_id); 400 if (it == m_windows.end()) { 401 did_misbehave("GetWindowRect: Bad window ID"); 402 return nullptr; 403 } 404 return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect()); 405} 406 407OwnPtr<Messages::WindowServer::SetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::SetClipboardContents& message) 408{ 409 auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id()); 410 if (!shared_buffer) { 411 did_misbehave("SetClipboardContents: Bad shared buffer ID"); 412 return nullptr; 413 } 414 Clipboard::the().set_data(*shared_buffer, message.content_size(), message.content_type()); 415 return make<Messages::WindowServer::SetClipboardContentsResponse>(); 416} 417 418OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::GetClipboardContents&) 419{ 420 auto& clipboard = Clipboard::the(); 421 422 i32 shbuf_id = -1; 423 if (clipboard.size()) { 424 // FIXME: Optimize case where an app is copy/pasting within itself. 425 // We can just reuse the SharedBuffer then, since it will have the same peer PID. 426 // It would be even nicer if a SharedBuffer could have an arbitrary number of clients.. 427 RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(clipboard.size()); 428 ASSERT(shared_buffer); 429 memcpy(shared_buffer->data(), clipboard.data(), clipboard.size()); 430 shared_buffer->seal(); 431 shared_buffer->share_with(client_pid()); 432 shbuf_id = shared_buffer->shbuf_id(); 433 434 // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them. 435 // After we respond to GetClipboardContents, we have to wait for the client to ref the buffer on his side. 436 m_last_sent_clipboard_content = move(shared_buffer); 437 } 438 return make<Messages::WindowServer::GetClipboardContentsResponse>(shbuf_id, clipboard.size(), clipboard.data_type()); 439} 440 441OwnPtr<Messages::WindowServer::CreateWindowResponse> ClientConnection::handle(const Messages::WindowServer::CreateWindow& message) 442{ 443 int window_id = m_next_window_id++; 444 auto window = Window::construct(*this, (WindowType)message.type(), window_id, message.modal(), message.minimizable(), message.resizable(), message.fullscreen()); 445 window->set_has_alpha_channel(message.has_alpha_channel()); 446 window->set_title(message.title()); 447 if (!message.fullscreen()) 448 window->set_rect(message.rect()); 449 window->set_show_titlebar(message.show_titlebar()); 450 window->set_opacity(message.opacity()); 451 window->set_size_increment(message.size_increment()); 452 window->set_base_size(message.base_size()); 453 window->invalidate(); 454 if (window->type() == WindowType::MenuApplet) 455 AppletManager::the().add_applet(*window); 456 m_windows.set(window_id, move(window)); 457 return make<Messages::WindowServer::CreateWindowResponse>(window_id); 458} 459 460OwnPtr<Messages::WindowServer::DestroyWindowResponse> ClientConnection::handle(const Messages::WindowServer::DestroyWindow& message) 461{ 462 auto it = m_windows.find(message.window_id()); 463 if (it == m_windows.end()) { 464 did_misbehave("DestroyWindow: Bad window ID"); 465 return nullptr; 466 } 467 auto& window = *(*it).value; 468 469 if (window.type() == WindowType::MenuApplet) 470 AppletManager::the().remove_applet(window); 471 472 WindowManager::the().invalidate(window); 473 remove_child(window); 474 ASSERT(it->value.ptr() == &window); 475 m_windows.remove(message.window_id()); 476 477 return make<Messages::WindowServer::DestroyWindowResponse>(); 478} 479 480void ClientConnection::post_paint_message(Window& window, bool ignore_occlusion) 481{ 482 auto rect_set = window.take_pending_paint_rects(); 483 if (window.is_minimized() || (!ignore_occlusion && window.is_occluded())) 484 return; 485 486 post_message(Messages::WindowClient::Paint(window.window_id(), window.size(), rect_set.rects())); 487} 488 489void ClientConnection::handle(const Messages::WindowServer::InvalidateRect& message) 490{ 491 auto it = m_windows.find(message.window_id()); 492 if (it == m_windows.end()) { 493 did_misbehave("InvalidateRect: Bad window ID"); 494 return; 495 } 496 auto& window = *(*it).value; 497 for (size_t i = 0; i < message.rects().size(); ++i) 498 window.request_update(message.rects()[i].intersected({ {}, window.size() }), message.ignore_occlusion()); 499} 500 501void ClientConnection::handle(const Messages::WindowServer::DidFinishPainting& message) 502{ 503 int window_id = message.window_id(); 504 auto it = m_windows.find(window_id); 505 if (it == m_windows.end()) { 506 did_misbehave("DidFinishPainting: Bad window ID"); 507 return; 508 } 509 auto& window = *(*it).value; 510 for (auto& rect : message.rects()) 511 WindowManager::the().invalidate(window, rect); 512 513 WindowSwitcher::the().refresh_if_needed(); 514} 515 516OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBackingStore& message) 517{ 518 int window_id = message.window_id(); 519 auto it = m_windows.find(window_id); 520 if (it == m_windows.end()) { 521 did_misbehave("SetWindowBackingStore: Bad window ID"); 522 return nullptr; 523 } 524 auto& window = *(*it).value; 525 if (window.last_backing_store() && window.last_backing_store()->shbuf_id() == message.shbuf_id()) { 526 window.swap_backing_stores(); 527 } else { 528 auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id()); 529 if (!shared_buffer) 530 return make<Messages::WindowServer::SetWindowBackingStoreResponse>(); 531 auto backing_store = Gfx::Bitmap::create_with_shared_buffer( 532 message.has_alpha_channel() ? Gfx::BitmapFormat::RGBA32 : Gfx::BitmapFormat::RGB32, 533 *shared_buffer, 534 message.size()); 535 window.set_backing_store(move(backing_store)); 536 } 537 538 if (message.flush_immediately()) 539 window.invalidate(); 540 541 return make<Messages::WindowServer::SetWindowBackingStoreResponse>(); 542} 543 544OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> ClientConnection::handle(const Messages::WindowServer::SetGlobalCursorTracking& message) 545{ 546 int window_id = message.window_id(); 547 auto it = m_windows.find(window_id); 548 if (it == m_windows.end()) { 549 did_misbehave("SetGlobalCursorTracking: Bad window ID"); 550 return nullptr; 551 } 552 it->value->set_global_cursor_tracking_enabled(message.enabled()); 553 return make<Messages::WindowServer::SetGlobalCursorTrackingResponse>(); 554} 555 556OwnPtr<Messages::WindowServer::SetWindowOverrideCursorResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOverrideCursor& message) 557{ 558 auto it = m_windows.find(message.window_id()); 559 if (it == m_windows.end()) { 560 did_misbehave("SetWindowOverrideCursor: Bad window ID"); 561 return nullptr; 562 } 563 auto& window = *(*it).value; 564 window.set_override_cursor(Cursor::create((StandardCursor)message.cursor_type())); 565 return make<Messages::WindowServer::SetWindowOverrideCursorResponse>(); 566} 567 568OwnPtr<Messages::WindowServer::SetWindowHasAlphaChannelResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowHasAlphaChannel& message) 569{ 570 auto it = m_windows.find(message.window_id()); 571 if (it == m_windows.end()) { 572 did_misbehave("SetWindowHasAlphaChannel: Bad window ID"); 573 return nullptr; 574 } 575 it->value->set_has_alpha_channel(message.has_alpha_channel()); 576 return make<Messages::WindowServer::SetWindowHasAlphaChannelResponse>(); 577} 578 579void ClientConnection::handle(const Messages::WindowServer::WM_SetActiveWindow& message) 580{ 581 auto* client = ClientConnection::from_client_id(message.client_id()); 582 if (!client) { 583 did_misbehave("WM_SetActiveWindow: Bad client ID"); 584 return; 585 } 586 auto it = client->m_windows.find(message.window_id()); 587 if (it == client->m_windows.end()) { 588 did_misbehave("WM_SetActiveWindow: Bad window ID"); 589 return; 590 } 591 auto& window = *(*it).value; 592 window.set_minimized(false); 593 WindowManager::the().move_to_front_and_make_active(window); 594} 595 596void ClientConnection::handle(const Messages::WindowServer::WM_PopupWindowMenu& message) 597{ 598 auto* client = ClientConnection::from_client_id(message.client_id()); 599 if (!client) { 600 did_misbehave("WM_PopupWindowMenu: Bad client ID"); 601 return; 602 } 603 auto it = client->m_windows.find(message.window_id()); 604 if (it == client->m_windows.end()) { 605 did_misbehave("WM_PopupWindowMenu: Bad window ID"); 606 return; 607 } 608 auto& window = *(*it).value; 609 window.popup_window_menu(message.screen_position()); 610} 611 612void ClientConnection::handle(const Messages::WindowServer::WM_StartWindowResize& request) 613{ 614 auto* client = ClientConnection::from_client_id(request.client_id()); 615 if (!client) { 616 did_misbehave("WM_StartWindowResize: Bad client ID"); 617 return; 618 } 619 auto it = client->m_windows.find(request.window_id()); 620 if (it == client->m_windows.end()) { 621 did_misbehave("WM_StartWindowResize: Bad window ID"); 622 return; 623 } 624 auto& window = *(*it).value; 625 // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button. 626 // Maybe the client should be allowed to specify what initiated this request? 627 WindowManager::the().start_window_resize(window, Screen::the().cursor_location(), MouseButton::Left); 628} 629 630void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowMinimized& message) 631{ 632 auto* client = ClientConnection::from_client_id(message.client_id()); 633 if (!client) { 634 did_misbehave("WM_SetWindowMinimized: Bad client ID"); 635 return; 636 } 637 auto it = client->m_windows.find(message.window_id()); 638 if (it == client->m_windows.end()) { 639 did_misbehave("WM_SetWindowMinimized: Bad window ID"); 640 return; 641 } 642 auto& window = *(*it).value; 643 window.set_minimized(message.minimized()); 644} 645 646OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&) 647{ 648 return make<Messages::WindowServer::GreetResponse>(client_id(), Screen::the().rect(), Gfx::current_system_theme_buffer_id()); 649} 650 651bool ClientConnection::is_showing_modal_window() const 652{ 653 for (auto& it : m_windows) { 654 auto& window = *it.value; 655 if (window.is_visible() && window.is_modal()) 656 return true; 657 } 658 return false; 659} 660 661void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowTaskbarRect& message) 662{ 663 auto* client = ClientConnection::from_client_id(message.client_id()); 664 if (!client) { 665 did_misbehave("WM_SetWindowTaskbarRect: Bad client ID"); 666 return; 667 } 668 auto it = client->m_windows.find(message.window_id()); 669 if (it == client->m_windows.end()) { 670 did_misbehave("WM_SetWindowTaskbarRect: Bad window ID"); 671 return; 672 } 673 auto& window = *(*it).value; 674 window.set_taskbar_rect(message.rect()); 675} 676 677OwnPtr<Messages::WindowServer::StartDragResponse> ClientConnection::handle(const Messages::WindowServer::StartDrag& message) 678{ 679 auto& wm = WindowManager::the(); 680 if (wm.dnd_client()) 681 return make<Messages::WindowServer::StartDragResponse>(false); 682 683 RefPtr<Gfx::Bitmap> bitmap; 684 if (message.bitmap_id() != -1) { 685 auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.bitmap_id()); 686 ssize_t size_in_bytes = message.bitmap_size().area() * sizeof(Gfx::RGBA32); 687 if (size_in_bytes > shared_buffer->size()) { 688 did_misbehave("SetAppletBackingStore: Shared buffer is too small for applet size"); 689 return nullptr; 690 } 691 bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *shared_buffer, message.bitmap_size()); 692 } 693 694 wm.start_dnd_drag(*this, message.text(), bitmap, message.data_type(), message.data()); 695 return make<Messages::WindowServer::StartDragResponse>(true); 696} 697 698OwnPtr<Messages::WindowServer::SetSystemMenuResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemMenu& message) 699{ 700 auto it = m_menus.find(message.menu_id()); 701 if (it == m_menus.end()) { 702 did_misbehave("SetSystemMenu called with invalid menu ID"); 703 return nullptr; 704 } 705 706 auto& menu = it->value; 707 MenuManager::the().set_system_menu(menu); 708 return make<Messages::WindowServer::SetSystemMenuResponse>(); 709} 710 711OwnPtr<Messages::WindowServer::SetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemTheme& message) 712{ 713 bool success = WindowManager::the().update_theme(message.theme_path(), message.theme_name()); 714 return make<Messages::WindowServer::SetSystemThemeResponse>(success); 715} 716 717void ClientConnection::boost() 718{ 719 // FIXME: Re-enable this when we have a solution for boosting. 720#if 0 721 if (set_process_boost(client_pid(), 10) < 0) 722 perror("boost: set_process_boost"); 723#endif 724} 725 726void ClientConnection::deboost() 727{ 728 // FIXME: Re-enable this when we have a solution for boosting. 729#if 0 730 if (set_process_boost(client_pid(), 0) < 0) 731 perror("deboost: set_process_boost"); 732#endif 733} 734 735OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement& message) 736{ 737 auto it = m_windows.find(message.window_id()); 738 if (it == m_windows.end()) { 739 did_misbehave("SetWindowBaseSizeAndSizeIncrementResponse: Bad window ID"); 740 return nullptr; 741 } 742 743 auto& window = *it->value; 744 window.set_base_size(message.base_size()); 745 window.set_size_increment(message.size_increment()); 746 747 return make<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse>(); 748} 749 750void ClientConnection::handle(const Messages::WindowServer::EnableDisplayLink&) 751{ 752 m_has_display_link = true; 753} 754 755void ClientConnection::handle(const Messages::WindowServer::DisableDisplayLink&) 756{ 757 m_has_display_link = false; 758} 759 760void ClientConnection::notify_display_link(Badge<Compositor>) 761{ 762 if (!m_has_display_link) 763 return; 764 765 post_message(Messages::WindowClient::DisplayLinkNotification()); 766} 767 768}