WSClientConnection.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. #include <LibC/SharedBuffer.h>
  2. #include <LibDraw/GraphicsBitmap.h>
  3. #include <SharedBuffer.h>
  4. #include <WindowServer/WSAPITypes.h>
  5. #include <WindowServer/WSClientConnection.h>
  6. #include <WindowServer/WSClipboard.h>
  7. #include <WindowServer/WSCompositor.h>
  8. #include <WindowServer/WSEventLoop.h>
  9. #include <WindowServer/WSMenu.h>
  10. #include <WindowServer/WSMenuBar.h>
  11. #include <WindowServer/WSMenuItem.h>
  12. #include <WindowServer/WSScreen.h>
  13. #include <WindowServer/WSWindow.h>
  14. #include <WindowServer/WSWindowManager.h>
  15. #include <WindowServer/WSWindowSwitcher.h>
  16. #include <errno.h>
  17. #include <stdio.h>
  18. #include <sys/ioctl.h>
  19. #include <sys/socket.h>
  20. #include <sys/uio.h>
  21. #include <unistd.h>
  22. HashMap<int, WSClientConnection*>* s_connections;
  23. void WSClientConnection::for_each_client(Function<void(WSClientConnection&)> callback)
  24. {
  25. if (!s_connections)
  26. return;
  27. for (auto& it : *s_connections) {
  28. callback(*it.value);
  29. }
  30. }
  31. WSClientConnection* WSClientConnection::from_client_id(int client_id)
  32. {
  33. if (!s_connections)
  34. return nullptr;
  35. auto it = s_connections->find(client_id);
  36. if (it == s_connections->end())
  37. return nullptr;
  38. return (*it).value;
  39. }
  40. WSClientConnection::WSClientConnection(CLocalSocket& client_socket, int client_id)
  41. : Connection(client_socket, client_id)
  42. {
  43. if (!s_connections)
  44. s_connections = new HashMap<int, WSClientConnection*>;
  45. s_connections->set(client_id, this);
  46. }
  47. WSClientConnection::~WSClientConnection()
  48. {
  49. // NOTE: Move the windows out of 'm_windows' before teardown. This prevents code
  50. // that runs in response to window destruction from trying to iterate over
  51. // a partially destroyed window list.
  52. auto windows = move(m_windows);
  53. s_connections->remove(client_id());
  54. }
  55. void WSClientConnection::send_greeting()
  56. {
  57. WSAPI_ServerMessage message;
  58. message.type = WSAPI_ServerMessage::Type::Greeting;
  59. message.greeting.server_pid = getpid();
  60. message.greeting.your_client_id = client_id();
  61. message.greeting.screen_rect = WSScreen::the().rect();
  62. post_message(message);
  63. }
  64. void WSClientConnection::post_error(const String& error_message)
  65. {
  66. dbgprintf("WSClientConnection::post_error: client_id=%d: %s\n", client_id(), error_message.characters());
  67. WSAPI_ServerMessage message;
  68. message.type = WSAPI_ServerMessage::Type::Error;
  69. ASSERT(error_message.length() < (ssize_t)sizeof(message.text));
  70. strcpy(message.text, error_message.characters());
  71. message.text_length = error_message.length();
  72. post_message(message);
  73. }
  74. void WSClientConnection::notify_about_new_screen_rect(const Rect& rect)
  75. {
  76. WSAPI_ServerMessage message;
  77. message.type = WSAPI_ServerMessage::Type::ScreenRectChanged;
  78. message.screen.rect = rect;
  79. post_message(message);
  80. }
  81. void WSClientConnection::event(CEvent& event)
  82. {
  83. if (static_cast<WSEvent&>(event).is_client_request()) {
  84. on_request(static_cast<const WSAPIClientRequest&>(event));
  85. return;
  86. }
  87. Connection::event(event);
  88. }
  89. static Vector<Rect, 32> get_rects(const WSAPI_ClientMessage& message, const ByteBuffer& extra_data)
  90. {
  91. Vector<Rect, 32> rects;
  92. if (message.rect_count > (int)(WSAPI_ClientMessage::max_inline_rect_count + extra_data.size() / sizeof(WSAPI_Rect))) {
  93. return {};
  94. }
  95. for (int i = 0; i < min(WSAPI_ClientMessage::max_inline_rect_count, message.rect_count); ++i)
  96. rects.append(message.rects[i]);
  97. if (!extra_data.is_empty()) {
  98. auto* extra_rects = reinterpret_cast<const WSAPI_Rect*>(extra_data.data());
  99. for (int i = 0; i < (int)(extra_data.size() / sizeof(WSAPI_Rect)); ++i)
  100. rects.append(extra_rects[i]);
  101. }
  102. return rects;
  103. }
  104. bool WSClientConnection::handle_message(const WSAPI_ClientMessage& message, const ByteBuffer&& extra_data)
  105. {
  106. switch (message.type) {
  107. case WSAPI_ClientMessage::Type::Greeting:
  108. set_client_pid(message.greeting.client_pid);
  109. break;
  110. case WSAPI_ClientMessage::Type::CreateMenubar:
  111. CEventLoop::current().post_event(*this, make<WSAPICreateMenubarRequest>(client_id()));
  112. break;
  113. case WSAPI_ClientMessage::Type::DestroyMenubar:
  114. CEventLoop::current().post_event(*this, make<WSAPIDestroyMenubarRequest>(client_id(), message.menu.menubar_id));
  115. break;
  116. case WSAPI_ClientMessage::Type::SetApplicationMenubar:
  117. CEventLoop::current().post_event(*this, make<WSAPISetApplicationMenubarRequest>(client_id(), message.menu.menubar_id));
  118. break;
  119. case WSAPI_ClientMessage::Type::AddMenuToMenubar:
  120. CEventLoop::current().post_event(*this, make<WSAPIAddMenuToMenubarRequest>(client_id(), message.menu.menubar_id, message.menu.menu_id));
  121. break;
  122. case WSAPI_ClientMessage::Type::CreateMenu:
  123. if (message.text_length > (int)sizeof(message.text)) {
  124. did_misbehave();
  125. return false;
  126. }
  127. CEventLoop::current().post_event(*this, make<WSAPICreateMenuRequest>(client_id(), String(message.text, message.text_length)));
  128. break;
  129. case WSAPI_ClientMessage::Type::PopupMenu:
  130. CEventLoop::current().post_event(*this, make<WSAPIPopupMenuRequest>(client_id(), message.menu.menu_id, message.menu.position));
  131. break;
  132. case WSAPI_ClientMessage::Type::DismissMenu:
  133. CEventLoop::current().post_event(*this, make<WSAPIDismissMenuRequest>(client_id(), message.menu.menu_id));
  134. break;
  135. case WSAPI_ClientMessage::Type::SetWindowIconBitmap:
  136. CEventLoop::current().post_event(*this, make<WSAPISetWindowIconBitmapRequest>(client_id(), message.window_id, message.window.icon_buffer_id, message.window.icon_size));
  137. break;
  138. case WSAPI_ClientMessage::Type::DestroyMenu:
  139. CEventLoop::current().post_event(*this, make<WSAPIDestroyMenuRequest>(client_id(), message.menu.menu_id));
  140. break;
  141. case WSAPI_ClientMessage::Type::AddMenuItem:
  142. if (message.text_length > (int)sizeof(message.text)) {
  143. did_misbehave();
  144. return false;
  145. }
  146. if (message.menu.shortcut_text_length > (int)sizeof(message.menu.shortcut_text)) {
  147. did_misbehave();
  148. return false;
  149. }
  150. CEventLoop::current().post_event(*this, make<WSAPIAddMenuItemRequest>(client_id(), message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked, message.menu.icon_buffer_id));
  151. break;
  152. case WSAPI_ClientMessage::Type::UpdateMenuItem:
  153. if (message.text_length > (int)sizeof(message.text)) {
  154. did_misbehave();
  155. return false;
  156. }
  157. if (message.menu.shortcut_text_length > (int)sizeof(message.menu.shortcut_text)) {
  158. did_misbehave();
  159. return false;
  160. }
  161. CEventLoop::current().post_event(*this, make<WSAPIUpdateMenuItemRequest>(client_id(), message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked));
  162. break;
  163. case WSAPI_ClientMessage::Type::AddMenuSeparator:
  164. CEventLoop::current().post_event(*this, make<WSAPIAddMenuSeparatorRequest>(client_id(), message.menu.menu_id));
  165. break;
  166. case WSAPI_ClientMessage::Type::CreateWindow: {
  167. if (message.text_length > (int)sizeof(message.text)) {
  168. did_misbehave();
  169. return false;
  170. }
  171. auto ws_window_type = WSWindowType::Invalid;
  172. switch (message.window.type) {
  173. case WSAPI_WindowType::Normal:
  174. ws_window_type = WSWindowType::Normal;
  175. break;
  176. case WSAPI_WindowType::Menu:
  177. ws_window_type = WSWindowType::Menu;
  178. break;
  179. case WSAPI_WindowType::WindowSwitcher:
  180. ws_window_type = WSWindowType::WindowSwitcher;
  181. break;
  182. case WSAPI_WindowType::Taskbar:
  183. ws_window_type = WSWindowType::Taskbar;
  184. break;
  185. case WSAPI_WindowType::Tooltip:
  186. ws_window_type = WSWindowType::Tooltip;
  187. break;
  188. case WSAPI_WindowType::Menubar:
  189. ws_window_type = WSWindowType::Menubar;
  190. break;
  191. case WSAPI_WindowType::Launcher:
  192. ws_window_type = WSWindowType::Launcher;
  193. break;
  194. case WSAPI_WindowType::Invalid:
  195. default:
  196. dbgprintf("Unknown WSAPI_WindowType: %d\n", message.window.type);
  197. did_misbehave();
  198. return false;
  199. }
  200. CEventLoop::current().post_event(*this,
  201. make<WSAPICreateWindowRequest>(client_id(),
  202. message.window.rect,
  203. String(message.text, message.text_length),
  204. message.window.has_alpha_channel,
  205. message.window.modal,
  206. message.window.resizable,
  207. message.window.fullscreen,
  208. message.window.show_titlebar,
  209. message.window.opacity,
  210. message.window.base_size,
  211. message.window.size_increment,
  212. ws_window_type,
  213. Color::from_rgba(message.window.background_color)));
  214. break;
  215. }
  216. case WSAPI_ClientMessage::Type::DestroyWindow:
  217. CEventLoop::current().post_event(*this, make<WSAPIDestroyWindowRequest>(client_id(), message.window_id));
  218. break;
  219. case WSAPI_ClientMessage::Type::SetWindowTitle:
  220. if (message.text_length > (int)sizeof(message.text)) {
  221. did_misbehave();
  222. return false;
  223. }
  224. CEventLoop::current().post_event(*this, make<WSAPISetWindowTitleRequest>(client_id(), message.window_id, String(message.text, message.text_length)));
  225. break;
  226. case WSAPI_ClientMessage::Type::GetWindowTitle:
  227. CEventLoop::current().post_event(*this, make<WSAPIGetWindowTitleRequest>(client_id(), message.window_id));
  228. break;
  229. case WSAPI_ClientMessage::Type::SetWindowRect:
  230. CEventLoop::current().post_event(*this, make<WSAPISetWindowRectRequest>(client_id(), message.window_id, message.window.rect));
  231. break;
  232. case WSAPI_ClientMessage::Type::GetWindowRect:
  233. CEventLoop::current().post_event(*this, make<WSAPIGetWindowRectRequest>(client_id(), message.window_id));
  234. break;
  235. case WSAPI_ClientMessage::Type::SetClipboardContents:
  236. CEventLoop::current().post_event(*this, make<WSAPISetClipboardContentsRequest>(client_id(), message.clipboard.shared_buffer_id, message.clipboard.contents_size));
  237. break;
  238. case WSAPI_ClientMessage::Type::GetClipboardContents:
  239. CEventLoop::current().post_event(*this, make<WSAPIGetClipboardContentsRequest>(client_id()));
  240. break;
  241. case WSAPI_ClientMessage::Type::InvalidateRect: {
  242. auto rects = get_rects(message, extra_data);
  243. if (rects.is_empty()) {
  244. did_misbehave();
  245. return false;
  246. }
  247. CEventLoop::current().post_event(*this, make<WSAPIInvalidateRectRequest>(client_id(), message.window_id, rects));
  248. break;
  249. }
  250. case WSAPI_ClientMessage::Type::DidFinishPainting: {
  251. auto rects = get_rects(message, extra_data);
  252. if (rects.is_empty()) {
  253. did_misbehave();
  254. return false;
  255. }
  256. CEventLoop::current().post_event(*this, make<WSAPIDidFinishPaintingNotification>(client_id(), message.window_id, rects));
  257. break;
  258. }
  259. case WSAPI_ClientMessage::Type::GetWindowBackingStore:
  260. CEventLoop::current().post_event(*this, make<WSAPIGetWindowBackingStoreRequest>(client_id(), message.window_id));
  261. break;
  262. case WSAPI_ClientMessage::Type::SetWindowBackingStore:
  263. CEventLoop::current().post_event(*this, make<WSAPISetWindowBackingStoreRequest>(client_id(), message.window_id, message.backing.shared_buffer_id, message.backing.size, message.backing.bpp, message.backing.pitch, message.backing.has_alpha_channel, message.backing.flush_immediately));
  264. break;
  265. case WSAPI_ClientMessage::Type::SetGlobalCursorTracking:
  266. CEventLoop::current().post_event(*this, make<WSAPISetGlobalCursorTrackingRequest>(client_id(), message.window_id, message.value));
  267. break;
  268. case WSAPI_ClientMessage::Type::SetWallpaper:
  269. if (message.text_length > (int)sizeof(message.text)) {
  270. did_misbehave();
  271. return false;
  272. }
  273. CEventLoop::current().post_event(*this, make<WSAPISetWallpaperRequest>(client_id(), String(message.text, message.text_length)));
  274. break;
  275. case WSAPI_ClientMessage::Type::GetWallpaper:
  276. CEventLoop::current().post_event(*this, make<WSAPIGetWallpaperRequest>(client_id()));
  277. break;
  278. case WSAPI_ClientMessage::Type::SetWindowOverrideCursor:
  279. CEventLoop::current().post_event(*this, make<WSAPISetWindowOverrideCursorRequest>(client_id(), message.window_id, (WSStandardCursor)message.cursor.cursor));
  280. break;
  281. case WSAPI_ClientMessage::SetWindowHasAlphaChannel:
  282. CEventLoop::current().post_event(*this, make<WSAPISetWindowHasAlphaChannelRequest>(client_id(), message.window_id, message.value));
  283. break;
  284. case WSAPI_ClientMessage::Type::WM_SetActiveWindow:
  285. CEventLoop::current().post_event(*this, make<WSWMAPISetActiveWindowRequest>(client_id(), message.wm.client_id, message.wm.window_id));
  286. break;
  287. case WSAPI_ClientMessage::Type::WM_SetWindowMinimized:
  288. CEventLoop::current().post_event(*this, make<WSWMAPISetWindowMinimizedRequest>(client_id(), message.wm.client_id, message.wm.window_id, message.wm.minimized));
  289. break;
  290. case WSAPI_ClientMessage::Type::WM_StartWindowResize:
  291. CEventLoop::current().post_event(*this, make<WSWMAPIStartWindowResizeRequest>(client_id(), message.wm.client_id, message.wm.window_id));
  292. break;
  293. case WSAPI_ClientMessage::Type::WM_PopupWindowMenu:
  294. CEventLoop::current().post_event(*this, make<WSWMAPIPopupWindowMenuRequest>(client_id(), message.wm.client_id, message.wm.window_id, message.wm.position));
  295. break;
  296. case WSAPI_ClientMessage::Type::MoveWindowToFront:
  297. CEventLoop::current().post_event(*this, make<WSAPIMoveWindowToFrontRequest>(client_id(), message.window_id));
  298. break;
  299. default:
  300. break;
  301. }
  302. return true;
  303. }
  304. void WSClientConnection::handle_request(const WSAPICreateMenubarRequest&)
  305. {
  306. int menubar_id = m_next_menubar_id++;
  307. auto menubar = make<WSMenuBar>(*this, menubar_id);
  308. m_menubars.set(menubar_id, move(menubar));
  309. WSAPI_ServerMessage response;
  310. response.type = WSAPI_ServerMessage::Type::DidCreateMenubar;
  311. response.menu.menubar_id = menubar_id;
  312. post_message(response);
  313. }
  314. void WSClientConnection::handle_request(const WSAPIDestroyMenubarRequest& request)
  315. {
  316. int menubar_id = request.menubar_id();
  317. auto it = m_menubars.find(menubar_id);
  318. if (it == m_menubars.end()) {
  319. post_error("WSAPIDestroyMenubarRequest: Bad menubar ID");
  320. return;
  321. }
  322. auto& menubar = *(*it).value;
  323. WSWindowManager::the().close_menubar(menubar);
  324. m_menubars.remove(it);
  325. WSAPI_ServerMessage response;
  326. response.type = WSAPI_ServerMessage::Type::DidDestroyMenubar;
  327. response.menu.menubar_id = menubar_id;
  328. post_message(response);
  329. }
  330. void WSClientConnection::handle_request(const WSAPICreateMenuRequest& request)
  331. {
  332. int menu_id = m_next_menu_id++;
  333. auto menu = make<WSMenu>(this, menu_id, request.text());
  334. m_menus.set(menu_id, move(menu));
  335. WSAPI_ServerMessage response;
  336. response.type = WSAPI_ServerMessage::Type::DidCreateMenu;
  337. response.menu.menu_id = menu_id;
  338. post_message(response);
  339. }
  340. void WSClientConnection::handle_request(const WSAPIDestroyMenuRequest& request)
  341. {
  342. int menu_id = static_cast<const WSAPIDestroyMenuRequest&>(request).menu_id();
  343. auto it = m_menus.find(menu_id);
  344. if (it == m_menus.end()) {
  345. post_error("WSAPIDestroyMenuRequest: Bad menu ID");
  346. return;
  347. }
  348. auto& menu = *(*it).value;
  349. WSWindowManager::the().close_menu(menu);
  350. m_menus.remove(it);
  351. WSAPI_ServerMessage response;
  352. response.type = WSAPI_ServerMessage::Type::DidDestroyMenu;
  353. response.menu.menu_id = menu_id;
  354. post_message(response);
  355. }
  356. void WSClientConnection::handle_request(const WSAPISetApplicationMenubarRequest& request)
  357. {
  358. int menubar_id = request.menubar_id();
  359. auto it = m_menubars.find(menubar_id);
  360. if (it == m_menubars.end()) {
  361. post_error("WSAPISetApplicationMenubarRequest: Bad menubar ID");
  362. return;
  363. }
  364. auto& menubar = *(*it).value;
  365. m_app_menubar = menubar.make_weak_ptr();
  366. WSWindowManager::the().notify_client_changed_app_menubar(*this);
  367. WSAPI_ServerMessage response;
  368. response.type = WSAPI_ServerMessage::Type::DidSetApplicationMenubar;
  369. response.menu.menubar_id = menubar_id;
  370. post_message(response);
  371. }
  372. void WSClientConnection::handle_request(const WSAPIAddMenuToMenubarRequest& request)
  373. {
  374. int menubar_id = request.menubar_id();
  375. int menu_id = request.menu_id();
  376. auto it = m_menubars.find(menubar_id);
  377. auto jt = m_menus.find(menu_id);
  378. if (it == m_menubars.end()) {
  379. post_error("WSAPIAddMenuToMenubarRequest: Bad menubar ID");
  380. return;
  381. }
  382. if (jt == m_menus.end()) {
  383. post_error("WSAPIAddMenuToMenubarRequest: Bad menu ID");
  384. return;
  385. }
  386. auto& menubar = *(*it).value;
  387. auto& menu = *(*jt).value;
  388. menubar.add_menu(menu);
  389. WSAPI_ServerMessage response;
  390. response.type = WSAPI_ServerMessage::Type::DidAddMenuToMenubar;
  391. response.menu.menubar_id = menubar_id;
  392. response.menu.menu_id = menu_id;
  393. post_message(response);
  394. }
  395. void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
  396. {
  397. int menu_id = request.menu_id();
  398. unsigned identifier = request.identifier();
  399. auto it = m_menus.find(menu_id);
  400. if (it == m_menus.end()) {
  401. post_error("WSAPIAddMenuItemRequest: Bad menu ID");
  402. return;
  403. }
  404. auto& menu = *(*it).value;
  405. auto menu_item = make<WSMenuItem>(menu, identifier, request.text(), request.shortcut_text(), request.is_enabled(), request.is_checkable(), request.is_checked());
  406. if (request.icon_buffer_id() != -1) {
  407. auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(request.icon_buffer_id());
  408. if (!icon_buffer) {
  409. did_misbehave();
  410. return;
  411. }
  412. // FIXME: Verify that the icon buffer can accomodate a 16x16 bitmap view.
  413. auto shared_icon = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, icon_buffer.release_nonnull(), { 16, 16 });
  414. menu_item->set_icon(shared_icon);
  415. }
  416. menu.add_item(move(menu_item));
  417. WSAPI_ServerMessage response;
  418. response.type = WSAPI_ServerMessage::Type::DidAddMenuItem;
  419. response.menu.menu_id = menu_id;
  420. response.menu.identifier = identifier;
  421. post_message(response);
  422. }
  423. void WSClientConnection::handle_request(const WSAPIPopupMenuRequest& request)
  424. {
  425. int menu_id = request.menu_id();
  426. auto position = request.position();
  427. auto it = m_menus.find(menu_id);
  428. if (it == m_menus.end()) {
  429. post_error("WSAPIPopupMenuRequest: Bad menu ID");
  430. return;
  431. }
  432. auto& menu = *(*it).value;
  433. menu.popup(position);
  434. }
  435. void WSClientConnection::handle_request(const WSAPIDismissMenuRequest& request)
  436. {
  437. int menu_id = request.menu_id();
  438. auto it = m_menus.find(menu_id);
  439. if (it == m_menus.end()) {
  440. post_error("WSAPIDismissMenuRequest: Bad menu ID");
  441. return;
  442. }
  443. auto& menu = *(*it).value;
  444. menu.close();
  445. }
  446. void WSClientConnection::handle_request(const WSAPIUpdateMenuItemRequest& request)
  447. {
  448. int menu_id = request.menu_id();
  449. unsigned identifier = request.identifier();
  450. auto it = m_menus.find(menu_id);
  451. if (it == m_menus.end()) {
  452. post_error("WSAPIUpdateMenuItemRequest: Bad menu ID");
  453. return;
  454. }
  455. auto& menu = *(*it).value;
  456. auto* menu_item = menu.item_with_identifier(request.identifier());
  457. if (!menu_item) {
  458. post_error("WSAPIUpdateMenuItemRequest: Bad menu item identifier");
  459. return;
  460. }
  461. menu_item->set_text(request.text());
  462. menu_item->set_shortcut_text(request.shortcut_text());
  463. menu_item->set_enabled(request.is_enabled());
  464. menu_item->set_checkable(request.is_checkable());
  465. if (request.is_checkable())
  466. menu_item->set_checked(request.is_checked());
  467. WSAPI_ServerMessage response;
  468. response.type = WSAPI_ServerMessage::Type::DidUpdateMenuItem;
  469. response.menu.menu_id = menu_id;
  470. response.menu.identifier = identifier;
  471. post_message(response);
  472. }
  473. void WSClientConnection::handle_request(const WSAPIAddMenuSeparatorRequest& request)
  474. {
  475. int menu_id = request.menu_id();
  476. auto it = m_menus.find(menu_id);
  477. if (it == m_menus.end()) {
  478. post_error("WSAPIAddMenuSeparatorRequest: Bad menu ID");
  479. return;
  480. }
  481. auto& menu = *(*it).value;
  482. menu.add_item(make<WSMenuItem>(menu, WSMenuItem::Separator));
  483. WSAPI_ServerMessage response;
  484. response.type = WSAPI_ServerMessage::Type::DidAddMenuSeparator;
  485. response.menu.menu_id = menu_id;
  486. post_message(response);
  487. }
  488. void WSClientConnection::handle_request(const WSAPIMoveWindowToFrontRequest& request)
  489. {
  490. int window_id = request.window_id();
  491. auto it = m_windows.find(window_id);
  492. if (it == m_windows.end()) {
  493. post_error("WSAPIMoveWindowToFrontRequest: Bad window ID");
  494. return;
  495. }
  496. auto& window = *(*it).value;
  497. WSWindowManager::the().move_to_front_and_make_active(window);
  498. }
  499. void WSClientConnection::handle_request(const WSAPISetWindowOpacityRequest& request)
  500. {
  501. int window_id = request.window_id();
  502. auto it = m_windows.find(window_id);
  503. if (it == m_windows.end()) {
  504. post_error("WSAPISetWindowOpacityRequest: Bad window ID");
  505. return;
  506. }
  507. auto& window = *(*it).value;
  508. window.set_opacity(request.opacity());
  509. }
  510. void WSClientConnection::handle_request(const WSAPISetWallpaperRequest& request)
  511. {
  512. WSCompositor::the().set_wallpaper(request.wallpaper(), [&](bool success) {
  513. WSAPI_ServerMessage response;
  514. response.type = WSAPI_ServerMessage::Type::DidSetWallpaper;
  515. response.value = success;
  516. post_message(response);
  517. });
  518. }
  519. void WSClientConnection::handle_request(const WSAPIGetWallpaperRequest&)
  520. {
  521. auto path = WSCompositor::the().wallpaper_path();
  522. WSAPI_ServerMessage response;
  523. response.type = WSAPI_ServerMessage::Type::DidGetWallpaper;
  524. ASSERT(path.length() < (int)sizeof(response.text));
  525. memcpy(response.text, path.characters(), path.length() + 1);
  526. response.text_length = path.length();
  527. post_message(response);
  528. }
  529. void WSClientConnection::handle_request(const WSAPISetWindowTitleRequest& request)
  530. {
  531. int window_id = request.window_id();
  532. auto it = m_windows.find(window_id);
  533. if (it == m_windows.end()) {
  534. post_error("WSAPISetWindowTitleRequest: Bad window ID");
  535. return;
  536. }
  537. auto& window = *(*it).value;
  538. window.set_title(request.title());
  539. }
  540. void WSClientConnection::handle_request(const WSAPIGetWindowTitleRequest& request)
  541. {
  542. int window_id = request.window_id();
  543. auto it = m_windows.find(window_id);
  544. if (it == m_windows.end()) {
  545. post_error("WSAPIGetWindowTitleRequest: Bad window ID");
  546. return;
  547. }
  548. auto& window = *(*it).value;
  549. WSAPI_ServerMessage response;
  550. response.type = WSAPI_ServerMessage::Type::DidGetWindowTitle;
  551. response.window_id = window.window_id();
  552. ASSERT(window.title().length() < (ssize_t)sizeof(response.text));
  553. strcpy(response.text, window.title().characters());
  554. response.text_length = window.title().length();
  555. post_message(response);
  556. }
  557. void WSClientConnection::handle_request(const WSAPISetWindowIconBitmapRequest& request)
  558. {
  559. int window_id = request.window_id();
  560. auto it = m_windows.find(window_id);
  561. if (it == m_windows.end()) {
  562. post_error("WSAPISetWindowIconBitmapRequest: Bad window ID");
  563. return;
  564. }
  565. auto& window = *(*it).value;
  566. auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(request.icon_buffer_id());
  567. if (!icon_buffer) {
  568. window.set_default_icon();
  569. } else {
  570. window.set_icon(GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *icon_buffer, request.icon_size()));
  571. }
  572. window.frame().invalidate_title_bar();
  573. WSWindowManager::the().tell_wm_listeners_window_icon_changed(window);
  574. }
  575. void WSClientConnection::handle_request(const WSAPISetWindowRectRequest& request)
  576. {
  577. int window_id = request.window_id();
  578. auto it = m_windows.find(window_id);
  579. if (it == m_windows.end()) {
  580. post_error("WSAPISetWindowRectRequest: Bad window ID");
  581. return;
  582. }
  583. auto& window = *(*it).value;
  584. if (window.is_fullscreen()) {
  585. dbgprintf("WSClientConnection: Ignoring SetWindowRect request for fullscreen window\n");
  586. return;
  587. }
  588. window.set_rect(request.rect());
  589. window.request_update(request.rect());
  590. }
  591. void WSClientConnection::handle_request(const WSAPIGetWindowRectRequest& request)
  592. {
  593. int window_id = request.window_id();
  594. auto it = m_windows.find(window_id);
  595. if (it == m_windows.end()) {
  596. post_error("WSAPIGetWindowRectRequest: Bad window ID");
  597. return;
  598. }
  599. auto& window = *(*it).value;
  600. WSAPI_ServerMessage response;
  601. response.type = WSAPI_ServerMessage::Type::DidGetWindowRect;
  602. response.window_id = window.window_id();
  603. response.window.rect = window.rect();
  604. post_message(response);
  605. }
  606. void WSClientConnection::handle_request(const WSAPISetClipboardContentsRequest& request)
  607. {
  608. auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(request.shared_buffer_id());
  609. if (!shared_buffer) {
  610. post_error("WSAPISetClipboardContentsRequest: Bad shared buffer ID");
  611. return;
  612. }
  613. WSClipboard::the().set_data(*shared_buffer, request.size());
  614. WSAPI_ServerMessage response;
  615. response.type = WSAPI_ServerMessage::Type::DidSetClipboardContents;
  616. response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id();
  617. post_message(response);
  618. }
  619. void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&)
  620. {
  621. WSAPI_ServerMessage response;
  622. response.type = WSAPI_ServerMessage::Type::DidGetClipboardContents;
  623. response.clipboard.shared_buffer_id = -1;
  624. response.clipboard.contents_size = 0;
  625. if (WSClipboard::the().size()) {
  626. // FIXME: Optimize case where an app is copy/pasting within itself.
  627. // We can just reuse the SharedBuffer then, since it will have the same peer PID.
  628. // It would be even nicer if a SharedBuffer could have an arbitrary number of clients..
  629. RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(WSClipboard::the().size());
  630. ASSERT(shared_buffer);
  631. memcpy(shared_buffer->data(), WSClipboard::the().data(), WSClipboard::the().size());
  632. shared_buffer->seal();
  633. shared_buffer->share_with(client_pid());
  634. response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id();
  635. response.clipboard.contents_size = WSClipboard::the().size();
  636. // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them.
  637. // After we respond to GetClipboardContents, we have to wait for the client to ref the buffer on his side.
  638. m_last_sent_clipboard_content = move(shared_buffer);
  639. }
  640. post_message(response);
  641. }
  642. void WSClientConnection::handle_request(const WSAPICreateWindowRequest& request)
  643. {
  644. int window_id = m_next_window_id++;
  645. auto window = make<WSWindow>(*this, request.window_type(), window_id, request.is_modal(), request.is_resizable(), request.is_fullscreen());
  646. window->set_background_color(request.background_color());
  647. window->set_has_alpha_channel(request.has_alpha_channel());
  648. window->set_title(request.title());
  649. if (!request.is_fullscreen())
  650. window->set_rect(request.rect());
  651. window->set_show_titlebar(request.show_titlebar());
  652. window->set_opacity(request.opacity());
  653. window->set_size_increment(request.size_increment());
  654. window->set_base_size(request.base_size());
  655. window->invalidate();
  656. m_windows.set(window_id, move(window));
  657. WSAPI_ServerMessage response;
  658. response.type = WSAPI_ServerMessage::Type::DidCreateWindow;
  659. response.window_id = window_id;
  660. post_message(response);
  661. }
  662. void WSClientConnection::handle_request(const WSAPIDestroyWindowRequest& request)
  663. {
  664. int window_id = request.window_id();
  665. auto it = m_windows.find(window_id);
  666. if (it == m_windows.end()) {
  667. post_error("WSAPIDestroyWindowRequest: Bad window ID");
  668. return;
  669. }
  670. auto& window = *(*it).value;
  671. WSWindowManager::the().invalidate(window);
  672. m_windows.remove(it);
  673. WSAPI_ServerMessage response;
  674. response.type = WSAPI_ServerMessage::Type::DidDestroyWindow;
  675. response.window_id = window.window_id();
  676. post_message(response);
  677. }
  678. void WSClientConnection::post_paint_message(WSWindow& window)
  679. {
  680. auto rect_set = window.take_pending_paint_rects();
  681. if (window.is_minimized())
  682. return;
  683. WSAPI_ServerMessage message;
  684. message.type = WSAPI_ServerMessage::Type::Paint;
  685. message.window_id = window.window_id();
  686. auto& rects = rect_set.rects();
  687. message.rect_count = rects.size();
  688. for (int i = 0; i < min(WSAPI_ServerMessage::max_inline_rect_count, rects.size()); ++i)
  689. message.rects[i] = rects[i];
  690. message.paint.window_size = window.size();
  691. ByteBuffer extra_data;
  692. if (rects.size() > WSAPI_ServerMessage::max_inline_rect_count)
  693. extra_data = ByteBuffer::wrap(&rects[WSAPI_ServerMessage::max_inline_rect_count], (rects.size() - WSAPI_ServerMessage::max_inline_rect_count) * sizeof(WSAPI_Rect));
  694. post_message(message, extra_data);
  695. }
  696. void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& request)
  697. {
  698. int window_id = request.window_id();
  699. auto it = m_windows.find(window_id);
  700. if (it == m_windows.end()) {
  701. post_error("WSAPIInvalidateRectRequest: Bad window ID");
  702. return;
  703. }
  704. auto& window = *(*it).value;
  705. for (int i = 0; i < request.rects().size(); ++i)
  706. window.request_update(request.rects()[i].intersected({ {}, window.size() }));
  707. }
  708. void WSClientConnection::handle_request(const WSAPIDidFinishPaintingNotification& request)
  709. {
  710. int window_id = request.window_id();
  711. auto it = m_windows.find(window_id);
  712. if (it == m_windows.end()) {
  713. post_error("WSAPIDidFinishPaintingNotification: Bad window ID");
  714. return;
  715. }
  716. auto& window = *(*it).value;
  717. for (auto& rect : request.rects())
  718. WSWindowManager::the().invalidate(window, rect);
  719. WSWindowSwitcher::the().refresh_if_needed();
  720. }
  721. void WSClientConnection::handle_request(const WSAPIGetWindowBackingStoreRequest& request)
  722. {
  723. int window_id = request.window_id();
  724. auto it = m_windows.find(window_id);
  725. if (it == m_windows.end()) {
  726. post_error("WSAPIGetWindowBackingStoreRequest: Bad window ID");
  727. return;
  728. }
  729. auto& window = *(*it).value;
  730. auto* backing_store = window.backing_store();
  731. WSAPI_ServerMessage response;
  732. response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore;
  733. response.window_id = window_id;
  734. response.backing.bpp = sizeof(RGBA32);
  735. response.backing.pitch = backing_store->pitch();
  736. response.backing.size = backing_store->size();
  737. response.backing.has_alpha_channel = backing_store->has_alpha_channel();
  738. response.backing.shared_buffer_id = backing_store->shared_buffer_id();
  739. post_message(response);
  740. }
  741. void WSClientConnection::handle_request(const WSAPISetWindowBackingStoreRequest& request)
  742. {
  743. int window_id = request.window_id();
  744. auto it = m_windows.find(window_id);
  745. if (it == m_windows.end()) {
  746. post_error("WSAPISetWindowBackingStoreRequest: Bad window ID");
  747. return;
  748. }
  749. auto& window = *(*it).value;
  750. if (window.last_backing_store() && window.last_backing_store()->shared_buffer_id() == request.shared_buffer_id()) {
  751. window.swap_backing_stores();
  752. } else {
  753. auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(request.shared_buffer_id());
  754. if (!shared_buffer)
  755. return;
  756. auto backing_store = GraphicsBitmap::create_with_shared_buffer(
  757. request.has_alpha_channel() ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32,
  758. *shared_buffer,
  759. request.size());
  760. window.set_backing_store(move(backing_store));
  761. }
  762. if (request.flush_immediately())
  763. window.invalidate();
  764. WSAPI_ServerMessage response;
  765. response.type = WSAPI_ServerMessage::Type::DidSetWindowBackingStore;
  766. response.window_id = window_id;
  767. response.backing.shared_buffer_id = request.shared_buffer_id();
  768. post_message(response);
  769. }
  770. void WSClientConnection::handle_request(const WSAPISetGlobalCursorTrackingRequest& request)
  771. {
  772. int window_id = request.window_id();
  773. auto it = m_windows.find(window_id);
  774. if (it == m_windows.end()) {
  775. post_error("WSAPISetGlobalCursorTrackingRequest: Bad window ID");
  776. return;
  777. }
  778. auto& window = *(*it).value;
  779. window.set_global_cursor_tracking_enabled(request.value());
  780. }
  781. void WSClientConnection::handle_request(const WSAPISetWindowOverrideCursorRequest& request)
  782. {
  783. int window_id = request.window_id();
  784. auto it = m_windows.find(window_id);
  785. if (it == m_windows.end()) {
  786. post_error("WSAPISetWindowOverrideCursorRequest: Bad window ID");
  787. return;
  788. }
  789. auto& window = *(*it).value;
  790. window.set_override_cursor(WSCursor::create(request.cursor()));
  791. }
  792. void WSClientConnection::handle_request(const WSAPISetWindowHasAlphaChannelRequest& request)
  793. {
  794. int window_id = request.window_id();
  795. auto it = m_windows.find(window_id);
  796. if (it == m_windows.end()) {
  797. post_error("WSAPISetWindowHasAlphaChannelRequest: Bad window ID");
  798. return;
  799. }
  800. auto& window = *(*it).value;
  801. window.set_has_alpha_channel(request.value());
  802. WSAPI_ServerMessage response;
  803. response.type = WSAPI_ServerMessage::Type::DidSetWindowHasAlphaChannel;
  804. response.window_id = window_id;
  805. response.value = request.value();
  806. post_message(response);
  807. }
  808. void WSClientConnection::handle_request(const WSWMAPISetActiveWindowRequest& request)
  809. {
  810. auto* client = WSClientConnection::from_client_id(request.target_client_id());
  811. if (!client) {
  812. post_error("WSWMAPISetActiveWindowRequest: Bad client ID");
  813. return;
  814. }
  815. auto it = client->m_windows.find(request.target_window_id());
  816. if (it == client->m_windows.end()) {
  817. post_error("WSWMAPISetActiveWindowRequest: Bad window ID");
  818. return;
  819. }
  820. auto& window = *(*it).value;
  821. window.set_minimized(false);
  822. WSWindowManager::the().move_to_front_and_make_active(window);
  823. }
  824. void WSClientConnection::handle_request(const WSWMAPIPopupWindowMenuRequest& request)
  825. {
  826. auto* client = WSClientConnection::from_client_id(request.target_client_id());
  827. if (!client) {
  828. post_error("WSWMAPIPopupWindowMenuRequest: Bad client ID");
  829. return;
  830. }
  831. auto it = client->m_windows.find(request.target_window_id());
  832. if (it == client->m_windows.end()) {
  833. post_error("WSWMAPIPopupWindowMenuRequest: Bad window ID");
  834. return;
  835. }
  836. auto& window = *(*it).value;
  837. window.popup_window_menu(request.position());
  838. }
  839. void WSClientConnection::handle_request(const WSWMAPIStartWindowResizeRequest& request)
  840. {
  841. auto* client = WSClientConnection::from_client_id(request.target_client_id());
  842. if (!client) {
  843. post_error("WSWMAPIStartWindowResizeRequest: Bad client ID");
  844. return;
  845. }
  846. auto it = client->m_windows.find(request.target_window_id());
  847. if (it == client->m_windows.end()) {
  848. post_error("WSWMAPIStartWindowResizeRequest: Bad window ID");
  849. return;
  850. }
  851. auto& window = *(*it).value;
  852. // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button.
  853. // Maybe the client should be allowed to specify what initiated this request?
  854. WSWindowManager::the().start_window_resize(window, WSScreen::the().cursor_location(), MouseButton::Left);
  855. }
  856. void WSClientConnection::handle_request(const WSWMAPISetWindowMinimizedRequest& request)
  857. {
  858. auto* client = WSClientConnection::from_client_id(request.target_client_id());
  859. if (!client) {
  860. post_error("WSWMAPISetWindowMinimizedRequest: Bad client ID");
  861. return;
  862. }
  863. auto it = client->m_windows.find(request.target_window_id());
  864. if (it == client->m_windows.end()) {
  865. post_error("WSWMAPISetWindowMinimizedRequest: Bad window ID");
  866. return;
  867. }
  868. auto& window = *(*it).value;
  869. window.set_minimized(request.is_minimized());
  870. }
  871. void WSClientConnection::on_request(const WSAPIClientRequest& request)
  872. {
  873. switch (request.type()) {
  874. case WSEvent::APICreateMenubarRequest:
  875. return handle_request(static_cast<const WSAPICreateMenubarRequest&>(request));
  876. case WSEvent::APIDestroyMenubarRequest:
  877. return handle_request(static_cast<const WSAPIDestroyMenubarRequest&>(request));
  878. case WSEvent::APICreateMenuRequest:
  879. return handle_request(static_cast<const WSAPICreateMenuRequest&>(request));
  880. case WSEvent::APIDestroyMenuRequest:
  881. return handle_request(static_cast<const WSAPIDestroyMenuRequest&>(request));
  882. case WSEvent::APISetApplicationMenubarRequest:
  883. return handle_request(static_cast<const WSAPISetApplicationMenubarRequest&>(request));
  884. case WSEvent::APIAddMenuToMenubarRequest:
  885. return handle_request(static_cast<const WSAPIAddMenuToMenubarRequest&>(request));
  886. case WSEvent::APIAddMenuItemRequest:
  887. return handle_request(static_cast<const WSAPIAddMenuItemRequest&>(request));
  888. case WSEvent::APIAddMenuSeparatorRequest:
  889. return handle_request(static_cast<const WSAPIAddMenuSeparatorRequest&>(request));
  890. case WSEvent::APIUpdateMenuItemRequest:
  891. return handle_request(static_cast<const WSAPIUpdateMenuItemRequest&>(request));
  892. case WSEvent::APISetWindowTitleRequest:
  893. return handle_request(static_cast<const WSAPISetWindowTitleRequest&>(request));
  894. case WSEvent::APIGetWindowTitleRequest:
  895. return handle_request(static_cast<const WSAPIGetWindowTitleRequest&>(request));
  896. case WSEvent::APISetWindowRectRequest:
  897. return handle_request(static_cast<const WSAPISetWindowRectRequest&>(request));
  898. case WSEvent::APIGetWindowRectRequest:
  899. return handle_request(static_cast<const WSAPIGetWindowRectRequest&>(request));
  900. case WSEvent::APISetWindowIconBitmapRequest:
  901. return handle_request(static_cast<const WSAPISetWindowIconBitmapRequest&>(request));
  902. case WSEvent::APISetClipboardContentsRequest:
  903. return handle_request(static_cast<const WSAPISetClipboardContentsRequest&>(request));
  904. case WSEvent::APIGetClipboardContentsRequest:
  905. return handle_request(static_cast<const WSAPIGetClipboardContentsRequest&>(request));
  906. case WSEvent::APICreateWindowRequest:
  907. return handle_request(static_cast<const WSAPICreateWindowRequest&>(request));
  908. case WSEvent::APIDestroyWindowRequest:
  909. return handle_request(static_cast<const WSAPIDestroyWindowRequest&>(request));
  910. case WSEvent::APIInvalidateRectRequest:
  911. return handle_request(static_cast<const WSAPIInvalidateRectRequest&>(request));
  912. case WSEvent::APIDidFinishPaintingNotification:
  913. return handle_request(static_cast<const WSAPIDidFinishPaintingNotification&>(request));
  914. case WSEvent::APIGetWindowBackingStoreRequest:
  915. return handle_request(static_cast<const WSAPIGetWindowBackingStoreRequest&>(request));
  916. case WSEvent::APISetGlobalCursorTrackingRequest:
  917. return handle_request(static_cast<const WSAPISetGlobalCursorTrackingRequest&>(request));
  918. case WSEvent::APISetWindowOpacityRequest:
  919. return handle_request(static_cast<const WSAPISetWindowOpacityRequest&>(request));
  920. case WSEvent::APISetWindowBackingStoreRequest:
  921. return handle_request(static_cast<const WSAPISetWindowBackingStoreRequest&>(request));
  922. case WSEvent::APISetWallpaperRequest:
  923. return handle_request(static_cast<const WSAPISetWallpaperRequest&>(request));
  924. case WSEvent::APIGetWallpaperRequest:
  925. return handle_request(static_cast<const WSAPIGetWallpaperRequest&>(request));
  926. case WSEvent::APISetWindowOverrideCursorRequest:
  927. return handle_request(static_cast<const WSAPISetWindowOverrideCursorRequest&>(request));
  928. case WSEvent::WMAPISetActiveWindowRequest:
  929. return handle_request(static_cast<const WSWMAPISetActiveWindowRequest&>(request));
  930. case WSEvent::WMAPISetWindowMinimizedRequest:
  931. return handle_request(static_cast<const WSWMAPISetWindowMinimizedRequest&>(request));
  932. case WSEvent::WMAPIStartWindowResizeRequest:
  933. return handle_request(static_cast<const WSWMAPIStartWindowResizeRequest&>(request));
  934. case WSEvent::WMAPIPopupWindowMenuRequest:
  935. return handle_request(static_cast<const WSWMAPIPopupWindowMenuRequest&>(request));
  936. case WSEvent::APIPopupMenuRequest:
  937. return handle_request(static_cast<const WSAPIPopupMenuRequest&>(request));
  938. case WSEvent::APIDismissMenuRequest:
  939. return handle_request(static_cast<const WSAPIDismissMenuRequest&>(request));
  940. case WSEvent::APISetWindowHasAlphaChannelRequest:
  941. return handle_request(static_cast<const WSAPISetWindowHasAlphaChannelRequest&>(request));
  942. case WSEvent::APIMoveWindowToFrontRequest:
  943. return handle_request(static_cast<const WSAPIMoveWindowToFrontRequest&>(request));
  944. default:
  945. break;
  946. }
  947. }
  948. bool WSClientConnection::is_showing_modal_window() const
  949. {
  950. for (auto& it : m_windows) {
  951. auto& window = *it.value;
  952. if (window.is_visible() && window.is_modal())
  953. return true;
  954. }
  955. return false;
  956. }