Serenity Operating System
at portability 339 lines 14 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/SharedBuffer.h> 28#include <LibCore/EventLoop.h> 29#include <LibCore/MimeData.h> 30#include <LibGUI/Action.h> 31#include <LibGUI/Application.h> 32#include <LibGUI/Clipboard.h> 33#include <LibGUI/Desktop.h> 34#include <LibGUI/DragOperation.h> 35#include <LibGUI/Event.h> 36#include <LibGUI/Menu.h> 37#include <LibGUI/Widget.h> 38#include <LibGUI/Window.h> 39#include <LibGUI/WindowServerConnection.h> 40#include <LibGfx/Bitmap.h> 41#include <LibGfx/Palette.h> 42#include <LibGfx/SystemTheme.h> 43 44//#define GEVENTLOOP_DEBUG 45 46namespace GUI { 47 48WindowServerConnection& WindowServerConnection::the() 49{ 50 static WindowServerConnection* s_connection = nullptr; 51 if (!s_connection) 52 s_connection = new WindowServerConnection; 53 return *s_connection; 54} 55 56static void set_system_theme_from_shared_buffer_id(int id) 57{ 58 auto system_theme = SharedBuffer::create_from_shared_buffer_id(id); 59 ASSERT(system_theme); 60 Gfx::set_system_theme(*system_theme); 61 Application::the().set_system_palette(*system_theme); 62} 63 64void WindowServerConnection::handshake() 65{ 66 auto response = send_sync<Messages::WindowServer::Greet>(); 67 set_my_client_id(response->client_id()); 68 set_system_theme_from_shared_buffer_id(response->system_theme_buffer_id()); 69 Desktop::the().did_receive_screen_rect({}, response->screen_rect()); 70} 71 72void WindowServerConnection::handle(const Messages::WindowClient::UpdateSystemTheme& message) 73{ 74 set_system_theme_from_shared_buffer_id(message.system_theme_buffer_id()); 75 Window::update_all_windows({}); 76} 77 78void WindowServerConnection::handle(const Messages::WindowClient::Paint& message) 79{ 80#ifdef GEVENTLOOP_DEBUG 81 dbgprintf("WID=%d Paint\n", message.window_id()); 82#endif 83 if (auto* window = Window::from_window_id(message.window_id())) 84 Core::EventLoop::current().post_event(*window, make<MultiPaintEvent>(message.rects(), message.window_size())); 85} 86 87void WindowServerConnection::handle(const Messages::WindowClient::WindowResized& message) 88{ 89 if (auto* window = Window::from_window_id(message.window_id())) { 90 Core::EventLoop::current().post_event(*window, make<ResizeEvent>(message.old_rect().size(), message.new_rect().size())); 91 } 92} 93 94void WindowServerConnection::handle(const Messages::WindowClient::WindowActivated& message) 95{ 96#ifdef GEVENTLOOP_DEBUG 97 dbgprintf("(%d) WID=%d WindowActivated\n", getpid(), message.window_id()); 98#endif 99 if (auto* window = Window::from_window_id(message.window_id())) 100 Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowBecameActive)); 101} 102 103void WindowServerConnection::handle(const Messages::WindowClient::WindowDeactivated& message) 104{ 105#ifdef GEVENTLOOP_DEBUG 106 dbgprintf("(%d) WID=%d WindowDeactivated\n", getpid(), message.window_id()); 107#endif 108 if (auto* window = Window::from_window_id(message.window_id())) 109 Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowBecameInactive)); 110} 111 112void WindowServerConnection::handle(const Messages::WindowClient::WindowCloseRequest& message) 113{ 114 if (auto* window = Window::from_window_id(message.window_id())) 115 Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowCloseRequest)); 116} 117 118void WindowServerConnection::handle(const Messages::WindowClient::WindowEntered& message) 119{ 120 if (auto* window = Window::from_window_id(message.window_id())) 121 Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowEntered)); 122} 123 124void WindowServerConnection::handle(const Messages::WindowClient::WindowLeft& message) 125{ 126 if (auto* window = Window::from_window_id(message.window_id())) 127 Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowLeft)); 128} 129 130void WindowServerConnection::handle(const Messages::WindowClient::KeyDown& message) 131{ 132#ifdef GEVENTLOOP_DEBUG 133 dbgprintf("WID=%d KeyDown character=0x%02x\n", message.window_id(), message.character()); 134#endif 135 auto* window = Window::from_window_id(message.window_id()); 136 if (!window) 137 return; 138 139 auto key_event = make<KeyEvent>(Event::KeyDown, message.key(), message.modifiers()); 140 if (message.character() != '\0') { 141 char ch = message.character(); 142 key_event->m_text = String(&ch, 1); 143 } 144 145 Action* action = nullptr; 146 147 if (auto* focused_widget = window->focused_widget()) 148 action = focused_widget->action_for_key_event(*key_event); 149 150 if (!action) 151 action = window->action_for_key_event(*key_event); 152 153 if (!action) 154 action = Application::the().action_for_key_event(*key_event); 155 156 if (action && action->is_enabled()) { 157 action->activate(); 158 return; 159 } 160 Core::EventLoop::current().post_event(*window, move(key_event)); 161} 162 163void WindowServerConnection::handle(const Messages::WindowClient::KeyUp& message) 164{ 165#ifdef GEVENTLOOP_DEBUG 166 dbgprintf("WID=%d KeyUp character=0x%02x\n", message.window_id(), message.character()); 167#endif 168 auto* window = Window::from_window_id(message.window_id()); 169 if (!window) 170 return; 171 172 auto key_event = make<KeyEvent>(Event::KeyUp, message.key(), message.modifiers()); 173 if (message.character() != '\0') { 174 char ch = message.character(); 175 key_event->m_text = String(&ch, 1); 176 } 177 178 Core::EventLoop::current().post_event(*window, move(key_event)); 179} 180 181MouseButton to_gmousebutton(u32 button) 182{ 183 switch (button) { 184 case 0: 185 return MouseButton::None; 186 case 1: 187 return MouseButton::Left; 188 case 2: 189 return MouseButton::Right; 190 case 4: 191 return MouseButton::Middle; 192 default: 193 ASSERT_NOT_REACHED(); 194 break; 195 } 196} 197 198void WindowServerConnection::handle(const Messages::WindowClient::MouseDown& message) 199{ 200#ifdef GEVENTLOOP_DEBUG 201 dbgprintf("WID=%d MouseDown %d,%d,%d\n", message.window_id(), message.mouse_position().x(), message.mouse_position().y(), message.wheel_delta(); 202#endif 203 204 if (auto* window = Window::from_window_id(message.window_id())) 205 Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseDown, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta())); 206} 207 208void WindowServerConnection::handle(const Messages::WindowClient::MouseUp& message) 209{ 210#ifdef GEVENTLOOP_DEBUG 211 dbgprintf("WID=%d MouseUp %d,%d,%d\n", message.window_id(), message.mouse_position().x(), message.mouse_position().y(), message.wheel_delta(); 212#endif 213 214 if (auto* window = Window::from_window_id(message.window_id())) 215 Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseUp, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta())); 216} 217 218void WindowServerConnection::handle(const Messages::WindowClient::MouseMove& message) 219{ 220#ifdef GEVENTLOOP_DEBUG 221 dbgprintf("WID=%d MouseMove %d,%d,%d\n", message.window_id(), message.mouse_position().x(), message.mouse_position().y(), message.wheel_delta(); 222#endif 223 224 if (auto* window = Window::from_window_id(message.window_id())) { 225 if (message.is_drag()) 226 Core::EventLoop::current().post_event(*window, make<DragEvent>(Event::DragMove, message.mouse_position(), message.drag_data_type())); 227 else 228 Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseMove, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta())); 229 } 230} 231 232void WindowServerConnection::handle(const Messages::WindowClient::MouseDoubleClick& message) 233{ 234#ifdef GEVENTLOOP_DEBUG 235 dbgprintf("WID=%d MouseDoubleClick %d,%d,%d\n", message.window_id(), message.mouse_position().x(), message.mouse_position().y(), message.wheel_delta(); 236#endif 237 238 if (auto* window = Window::from_window_id(message.window_id())) 239 Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseDoubleClick, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta())); 240} 241 242void WindowServerConnection::handle(const Messages::WindowClient::MouseWheel& message) 243{ 244#ifdef GEVENTLOOP_DEBUG 245 dbgprintf("WID=%d MouseWheel %d,%d,%d\n", message.window_id(), message.mouse_position().x(), message.mouse_position().y(), message.wheel_delta(); 246#endif 247 248 if (auto* window = Window::from_window_id(message.window_id())) 249 Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseWheel, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta())); 250} 251 252void WindowServerConnection::handle(const Messages::WindowClient::MenuItemActivated& message) 253{ 254 auto* menu = Menu::from_menu_id(message.menu_id()); 255 if (!menu) { 256 dbgprintf("EventLoop received event for invalid menu ID %d\n", message.menu_id()); 257 return; 258 } 259 if (auto* action = menu->action_at(message.identifier())) 260 action->activate(menu); 261} 262 263void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowStateChanged& message) 264{ 265#ifdef GEVENTLOOP_DEBUG 266 dbgprintf("EventLoop: handle_wm_event: %d\n", (int)event.type); 267#endif 268 if (auto* window = Window::from_window_id(message.wm_id())) 269 Core::EventLoop::current().post_event(*window, make<WMWindowStateChangedEvent>(message.client_id(), message.window_id(), message.title(), message.rect(), message.is_active(), static_cast<WindowType>(message.window_type()), message.is_minimized())); 270} 271 272void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowRectChanged& message) 273{ 274#ifdef GEVENTLOOP_DEBUG 275 dbgprintf("EventLoop: handle_wm_event: %d\n", (int)event.type); 276#endif 277 if (auto* window = Window::from_window_id(message.wm_id())) 278 Core::EventLoop::current().post_event(*window, make<WMWindowRectChangedEvent>(message.client_id(), message.window_id(), message.rect())); 279} 280 281void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowIconBitmapChanged& message) 282{ 283#ifdef GEVENTLOOP_DEBUG 284 dbgprintf("EventLoop: handle_wm_event: %d\n", (int)event.type); 285#endif 286 if (auto* window = Window::from_window_id(message.wm_id())) 287 Core::EventLoop::current().post_event(*window, make<WMWindowIconBitmapChangedEvent>(message.client_id(), message.window_id(), message.icon_buffer_id(), message.icon_size())); 288} 289 290void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowRemoved& message) 291{ 292#ifdef GEVENTLOOP_DEBUG 293 dbgprintf("EventLoop: handle_wm_event: %d\n", (int)event.type); 294#endif 295 if (auto* window = Window::from_window_id(message.wm_id())) 296 Core::EventLoop::current().post_event(*window, make<WMWindowRemovedEvent>(message.client_id(), message.window_id())); 297} 298 299void WindowServerConnection::handle(const Messages::WindowClient::ScreenRectChanged& message) 300{ 301 Desktop::the().did_receive_screen_rect({}, message.rect()); 302} 303 304void WindowServerConnection::handle(const Messages::WindowClient::ClipboardContentsChanged& message) 305{ 306 Clipboard::the().did_receive_clipboard_contents_changed({}, message.content_type()); 307} 308 309void WindowServerConnection::handle(const Messages::WindowClient::AsyncSetWallpaperFinished&) 310{ 311 // This is handled manually by Desktop::set_wallpaper(). 312} 313 314void WindowServerConnection::handle(const Messages::WindowClient::DragDropped& message) 315{ 316 if (auto* window = Window::from_window_id(message.window_id())) { 317 auto mime_data = Core::MimeData::construct(); 318 mime_data->set_data(message.data_type(), message.data().to_byte_buffer()); 319 Core::EventLoop::current().post_event(*window, make<DropEvent>(message.mouse_position(), message.text(), mime_data)); 320 } 321} 322 323void WindowServerConnection::handle(const Messages::WindowClient::DragAccepted&) 324{ 325 DragOperation::notify_accepted({}); 326} 327 328void WindowServerConnection::handle(const Messages::WindowClient::DragCancelled&) 329{ 330 DragOperation::notify_cancelled({}); 331} 332 333void WindowServerConnection::handle(const Messages::WindowClient::WindowStateChanged& message) 334{ 335 if (auto* window = Window::from_window_id(message.window_id())) 336 window->notify_state_changed({}, message.minimized(), message.occluded()); 337} 338 339}