WSWindow.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #include "WSWindow.h"
  2. #include "WSEvent.h"
  3. #include "WSEventLoop.h"
  4. #include "WSScreen.h"
  5. #include "WSWindowManager.h"
  6. #include <WindowServer/WSAPITypes.h>
  7. #include <WindowServer/WSClientConnection.h>
  8. static String default_window_icon_path()
  9. {
  10. return "/res/icons/16x16/window.png";
  11. }
  12. static GraphicsBitmap& default_window_icon()
  13. {
  14. static GraphicsBitmap* s_icon;
  15. if (!s_icon)
  16. s_icon = GraphicsBitmap::load_from_file(default_window_icon_path()).leak_ref();
  17. return *s_icon;
  18. }
  19. WSWindow::WSWindow(CObject& parent, WSWindowType type)
  20. : CObject(&parent)
  21. , m_type(type)
  22. , m_icon(default_window_icon())
  23. , m_frame(*this)
  24. {
  25. WSWindowManager::the().add_window(*this);
  26. }
  27. WSWindow::WSWindow(WSClientConnection& client, WSWindowType window_type, int window_id, bool modal, bool resizable, bool fullscreen)
  28. : CObject(&client)
  29. , m_client(&client)
  30. , m_type(window_type)
  31. , m_modal(modal)
  32. , m_resizable(resizable)
  33. , m_fullscreen(fullscreen)
  34. , m_window_id(window_id)
  35. , m_icon(default_window_icon())
  36. , m_frame(*this)
  37. {
  38. // FIXME: This should not be hard-coded here.
  39. if (m_type == WSWindowType::Taskbar) {
  40. m_wm_event_mask = WSAPI_WMEventMask::WindowStateChanges | WSAPI_WMEventMask::WindowRemovals | WSAPI_WMEventMask::WindowIconChanges;
  41. m_listens_to_wm_events = true;
  42. }
  43. WSWindowManager::the().add_window(*this);
  44. }
  45. WSWindow::~WSWindow()
  46. {
  47. WSWindowManager::the().remove_window(*this);
  48. }
  49. void WSWindow::set_title(const String& title)
  50. {
  51. if (m_title == title)
  52. return;
  53. m_title = title;
  54. WSWindowManager::the().notify_title_changed(*this);
  55. }
  56. void WSWindow::set_rect(const Rect& rect)
  57. {
  58. Rect old_rect;
  59. if (m_rect == rect)
  60. return;
  61. old_rect = m_rect;
  62. m_rect = rect;
  63. if (!m_client && (!m_backing_store || old_rect.size() != rect.size())) {
  64. m_backing_store = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size());
  65. }
  66. m_frame.notify_window_rect_changed(old_rect, rect);
  67. }
  68. // FIXME: Just use the same types.
  69. static WSAPI_MouseButton to_api(MouseButton button)
  70. {
  71. switch (button) {
  72. case MouseButton::None:
  73. return WSAPI_MouseButton::NoButton;
  74. case MouseButton::Left:
  75. return WSAPI_MouseButton::Left;
  76. case MouseButton::Right:
  77. return WSAPI_MouseButton::Right;
  78. case MouseButton::Middle:
  79. return WSAPI_MouseButton::Middle;
  80. }
  81. ASSERT_NOT_REACHED();
  82. }
  83. void WSWindow::handle_mouse_event(const WSMouseEvent& event)
  84. {
  85. set_automatic_cursor_tracking_enabled(event.buttons() != 0);
  86. WSAPI_ServerMessage server_message;
  87. server_message.window_id = window_id();
  88. switch (event.type()) {
  89. case WSEvent::MouseMove:
  90. server_message.type = WSAPI_ServerMessage::Type::MouseMove;
  91. break;
  92. case WSEvent::MouseDown:
  93. server_message.type = WSAPI_ServerMessage::Type::MouseDown;
  94. break;
  95. case WSEvent::MouseDoubleClick:
  96. server_message.type = WSAPI_ServerMessage::Type::MouseDoubleClick;
  97. break;
  98. case WSEvent::MouseUp:
  99. server_message.type = WSAPI_ServerMessage::Type::MouseUp;
  100. break;
  101. case WSEvent::MouseWheel:
  102. server_message.type = WSAPI_ServerMessage::Type::MouseWheel;
  103. break;
  104. default:
  105. ASSERT_NOT_REACHED();
  106. }
  107. server_message.mouse.position = event.position();
  108. server_message.mouse.button = to_api(event.button());
  109. server_message.mouse.buttons = event.buttons();
  110. server_message.mouse.modifiers = event.modifiers();
  111. server_message.mouse.wheel_delta = event.wheel_delta();
  112. m_client->post_message(server_message);
  113. }
  114. static WSAPI_WindowType to_api(WSWindowType ws_type)
  115. {
  116. switch (ws_type) {
  117. case WSWindowType::Normal:
  118. return WSAPI_WindowType::Normal;
  119. case WSWindowType::Menu:
  120. return WSAPI_WindowType::Menu;
  121. case WSWindowType::WindowSwitcher:
  122. return WSAPI_WindowType::WindowSwitcher;
  123. case WSWindowType::Taskbar:
  124. return WSAPI_WindowType::Taskbar;
  125. case WSWindowType::Tooltip:
  126. return WSAPI_WindowType::Tooltip;
  127. case WSWindowType::Menubar:
  128. return WSAPI_WindowType::Menubar;
  129. case WSWindowType::Launcher:
  130. return WSAPI_WindowType::Launcher;
  131. default:
  132. ASSERT_NOT_REACHED();
  133. }
  134. }
  135. void WSWindow::set_minimized(bool minimized)
  136. {
  137. if (m_minimized == minimized)
  138. return;
  139. m_minimized = minimized;
  140. if (!minimized)
  141. request_update({ {}, size() });
  142. invalidate();
  143. WSWindowManager::the().notify_minimization_state_changed(*this);
  144. }
  145. void WSWindow::set_maximized(bool maximized)
  146. {
  147. if (m_maximized == maximized)
  148. return;
  149. m_maximized = maximized;
  150. auto old_rect = m_rect;
  151. if (maximized) {
  152. m_unmaximized_rect = m_rect;
  153. set_rect(WSWindowManager::the().maximized_window_rect(*this));
  154. } else {
  155. set_rect(m_unmaximized_rect);
  156. }
  157. m_frame.did_set_maximized({}, maximized);
  158. CEventLoop::current().post_event(*this, make<WSResizeEvent>(old_rect, m_rect));
  159. }
  160. void WSWindow::event(CEvent& event)
  161. {
  162. if (!m_client) {
  163. ASSERT(parent());
  164. event.ignore();
  165. return;
  166. }
  167. if (is_blocked_by_modal_window())
  168. return;
  169. WSAPI_ServerMessage server_message;
  170. server_message.window_id = window_id();
  171. if (static_cast<WSEvent&>(event).is_mouse_event())
  172. return handle_mouse_event(static_cast<const WSMouseEvent&>(event));
  173. switch (event.type()) {
  174. case WSEvent::WindowEntered:
  175. server_message.type = WSAPI_ServerMessage::Type::WindowEntered;
  176. break;
  177. case WSEvent::WindowLeft:
  178. server_message.type = WSAPI_ServerMessage::Type::WindowLeft;
  179. break;
  180. case WSEvent::KeyDown:
  181. server_message.type = WSAPI_ServerMessage::Type::KeyDown;
  182. server_message.key.character = static_cast<const WSKeyEvent&>(event).character();
  183. server_message.key.key = static_cast<const WSKeyEvent&>(event).key();
  184. server_message.key.modifiers = static_cast<const WSKeyEvent&>(event).modifiers();
  185. break;
  186. case WSEvent::KeyUp:
  187. server_message.type = WSAPI_ServerMessage::Type::KeyUp;
  188. server_message.key.character = static_cast<const WSKeyEvent&>(event).character();
  189. server_message.key.key = static_cast<const WSKeyEvent&>(event).key();
  190. server_message.key.modifiers = static_cast<const WSKeyEvent&>(event).modifiers();
  191. break;
  192. case WSEvent::WindowActivated:
  193. server_message.type = WSAPI_ServerMessage::Type::WindowActivated;
  194. break;
  195. case WSEvent::WindowDeactivated:
  196. server_message.type = WSAPI_ServerMessage::Type::WindowDeactivated;
  197. break;
  198. case WSEvent::WindowCloseRequest:
  199. server_message.type = WSAPI_ServerMessage::Type::WindowCloseRequest;
  200. break;
  201. case WSEvent::WindowResized:
  202. server_message.type = WSAPI_ServerMessage::Type::WindowResized;
  203. server_message.window.old_rect = static_cast<const WSResizeEvent&>(event).old_rect();
  204. server_message.window.rect = static_cast<const WSResizeEvent&>(event).rect();
  205. break;
  206. case WSEvent::WM_WindowRemoved: {
  207. auto& removed_event = static_cast<const WSWMWindowRemovedEvent&>(event);
  208. server_message.type = WSAPI_ServerMessage::Type::WM_WindowRemoved;
  209. server_message.wm.client_id = removed_event.client_id();
  210. server_message.wm.window_id = removed_event.window_id();
  211. break;
  212. }
  213. case WSEvent::WM_WindowStateChanged: {
  214. auto& changed_event = static_cast<const WSWMWindowStateChangedEvent&>(event);
  215. server_message.type = WSAPI_ServerMessage::Type::WM_WindowStateChanged;
  216. server_message.wm.client_id = changed_event.client_id();
  217. server_message.wm.window_id = changed_event.window_id();
  218. server_message.wm.is_active = changed_event.is_active();
  219. server_message.wm.is_minimized = changed_event.is_minimized();
  220. server_message.wm.window_type = to_api(changed_event.window_type());
  221. ASSERT(changed_event.title().length() < (int)sizeof(server_message.text));
  222. memcpy(server_message.text, changed_event.title().characters(), changed_event.title().length());
  223. server_message.text_length = changed_event.title().length();
  224. server_message.wm.rect = changed_event.rect();
  225. break;
  226. }
  227. case WSEvent::WM_WindowIconBitmapChanged: {
  228. auto& changed_event = static_cast<const WSWMWindowIconBitmapChangedEvent&>(event);
  229. server_message.type = WSAPI_ServerMessage::Type::WM_WindowIconBitmapChanged;
  230. server_message.wm.client_id = changed_event.client_id();
  231. server_message.wm.window_id = changed_event.window_id();
  232. server_message.wm.icon_buffer_id = changed_event.icon_buffer_id();
  233. server_message.wm.icon_size = changed_event.icon_size();
  234. // FIXME: Perhaps we should update the bitmap sharing list somewhere else instead?
  235. ASSERT(client());
  236. dbg() << "WindowServer: Sharing icon buffer " << changed_event.icon_buffer_id() << " with PID " << client()->client_pid();
  237. if (share_buffer_with(changed_event.icon_buffer_id(), client()->client_pid()) < 0) {
  238. ASSERT_NOT_REACHED();
  239. }
  240. break;
  241. }
  242. case WSEvent::WM_WindowRectChanged: {
  243. auto& changed_event = static_cast<const WSWMWindowRectChangedEvent&>(event);
  244. server_message.type = WSAPI_ServerMessage::Type::WM_WindowRectChanged;
  245. server_message.wm.client_id = changed_event.client_id();
  246. server_message.wm.window_id = changed_event.window_id();
  247. server_message.wm.rect = changed_event.rect();
  248. break;
  249. }
  250. default:
  251. break;
  252. }
  253. if (server_message.type == WSAPI_ServerMessage::Type::Invalid)
  254. return;
  255. m_client->post_message(server_message);
  256. }
  257. void WSWindow::set_global_cursor_tracking_enabled(bool enabled)
  258. {
  259. m_global_cursor_tracking_enabled = enabled;
  260. }
  261. void WSWindow::set_visible(bool b)
  262. {
  263. if (m_visible == b)
  264. return;
  265. m_visible = b;
  266. invalidate();
  267. }
  268. void WSWindow::invalidate()
  269. {
  270. WSWindowManager::the().invalidate(*this);
  271. }
  272. bool WSWindow::is_active() const
  273. {
  274. return WSWindowManager::the().active_window() == this;
  275. }
  276. bool WSWindow::is_blocked_by_modal_window() const
  277. {
  278. return !is_modal() && client() && client()->is_showing_modal_window();
  279. }
  280. void WSWindow::set_default_icon()
  281. {
  282. m_icon = default_window_icon();
  283. }
  284. void WSWindow::request_update(const Rect& rect)
  285. {
  286. if (m_pending_paint_rects.is_empty()) {
  287. deferred_invoke([this](auto&) {
  288. client()->post_paint_message(*this);
  289. });
  290. }
  291. m_pending_paint_rects.add(rect);
  292. }
  293. void WSWindow::popup_window_menu(const Point& position)
  294. {
  295. if (!m_window_menu) {
  296. m_window_menu = make<WSMenu>(nullptr, -1, "(Window Menu)");
  297. m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 1, "Minimize"));
  298. m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 2, "Unminimize"));
  299. m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, WSMenuItem::Type::Separator));
  300. m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 3, "Close"));
  301. m_window_menu->on_item_activation = [&](auto& item) {
  302. switch (item.identifier()) {
  303. case 1:
  304. set_minimized(true);
  305. break;
  306. case 2:
  307. set_minimized(false);
  308. break;
  309. case 3:
  310. request_close();
  311. break;
  312. }
  313. };
  314. }
  315. m_window_menu->popup(position);
  316. }
  317. void WSWindow::request_close()
  318. {
  319. WSEvent close_request(WSEvent::WindowCloseRequest);
  320. event(close_request);
  321. }
  322. void WSWindow::set_fullscreen(bool fullscreen)
  323. {
  324. if (m_fullscreen == fullscreen)
  325. return;
  326. m_fullscreen = fullscreen;
  327. Rect new_window_rect = m_rect;
  328. if (m_fullscreen) {
  329. m_saved_nonfullscreen_rect = m_rect;
  330. new_window_rect = WSScreen::the().rect();
  331. } else if (!m_saved_nonfullscreen_rect.is_empty()) {
  332. new_window_rect = m_saved_nonfullscreen_rect;
  333. }
  334. CEventLoop::current().post_event(*this, make<WSResizeEvent>(m_rect, new_window_rect));
  335. set_rect(new_window_rect);
  336. }