WSClientConnection.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. #include <WindowServer/WSClientConnection.h>
  2. #include <WindowServer/WSMessageLoop.h>
  3. #include <WindowServer/WSMenuBar.h>
  4. #include <WindowServer/WSMenu.h>
  5. #include <WindowServer/WSMenuItem.h>
  6. #include <WindowServer/WSWindow.h>
  7. #include <WindowServer/WSWindowManager.h>
  8. #include <WindowServer/WSAPITypes.h>
  9. #include <WindowServer/WSClipboard.h>
  10. #include <SharedBuffer.h>
  11. #include <sys/ioctl.h>
  12. #include <unistd.h>
  13. #include <errno.h>
  14. #include <stdio.h>
  15. HashMap<int, WSClientConnection*>* s_connections;
  16. void WSClientConnection::for_each_client(Function<void(WSClientConnection&)> callback)
  17. {
  18. if (!s_connections)
  19. return;
  20. for (auto& it : *s_connections) {
  21. callback(*it.value);
  22. }
  23. }
  24. WSClientConnection* WSClientConnection::from_client_id(int client_id)
  25. {
  26. if (!s_connections)
  27. return nullptr;
  28. auto it = s_connections->find(client_id);
  29. if (it == s_connections->end())
  30. return nullptr;
  31. return (*it).value;
  32. }
  33. WSClientConnection::WSClientConnection(int fd)
  34. : m_fd(fd)
  35. {
  36. static int s_next_client_id = 0;
  37. m_client_id = ++s_next_client_id;
  38. int rc = ioctl(m_fd, 413, (int)&m_pid);
  39. ASSERT(rc == 0);
  40. if (!s_connections)
  41. s_connections = new HashMap<int, WSClientConnection*>;
  42. s_connections->set(m_client_id, this);
  43. WSAPI_ServerMessage message;
  44. message.type = WSAPI_ServerMessage::Type::Greeting;
  45. message.greeting.server_pid = getpid();
  46. post_message(message);
  47. }
  48. WSClientConnection::~WSClientConnection()
  49. {
  50. s_connections->remove(m_client_id);
  51. int rc = close(m_fd);
  52. ASSERT(rc == 0);
  53. }
  54. void WSClientConnection::post_error(const String& error_message)
  55. {
  56. dbgprintf("WSClientConnection::post_error: client_id=%d: %s\n", m_client_id, error_message.characters());
  57. WSAPI_ServerMessage message;
  58. message.type = WSAPI_ServerMessage::Type::Error;
  59. ASSERT(error_message.length() < (ssize_t)sizeof(message.text));
  60. strcpy(message.text, error_message.characters());
  61. message.text_length = error_message.length();
  62. post_message(message);
  63. }
  64. void WSClientConnection::post_message(const WSAPI_ServerMessage& message)
  65. {
  66. int nwritten = write(m_fd, &message, sizeof(message));
  67. if (nwritten < 0) {
  68. if (errno == EPIPE) {
  69. dbgprintf("WSClientConnection::post_message: Disconnected from peer.\n");
  70. return;
  71. }
  72. perror("WSClientConnection::post_message write");
  73. ASSERT_NOT_REACHED();
  74. }
  75. ASSERT(nwritten == sizeof(message));
  76. }
  77. RetainPtr<GraphicsBitmap> WSClientConnection::create_shared_bitmap(GraphicsBitmap::Format format, const Size& size)
  78. {
  79. auto shared_buffer = SharedBuffer::create(m_pid, size.area() * sizeof(RGBA32));
  80. ASSERT(shared_buffer);
  81. return GraphicsBitmap::create_with_shared_buffer(format, *shared_buffer, size);
  82. }
  83. void WSClientConnection::on_message(WSMessage& message)
  84. {
  85. if (message.is_client_request()) {
  86. on_request(static_cast<WSAPIClientRequest&>(message));
  87. return;
  88. }
  89. if (message.type() == WSMessage::WM_ClientDisconnected) {
  90. int client_id = static_cast<WSClientDisconnectedNotification&>(message).client_id();
  91. dbgprintf("WSClientConnection: Client disconnected: %d\n", client_id);
  92. delete this;
  93. return;
  94. }
  95. }
  96. void WSClientConnection::handle_request(WSAPICreateMenubarRequest&)
  97. {
  98. int menubar_id = m_next_menubar_id++;
  99. auto menubar = make<WSMenuBar>(*this, menubar_id);
  100. m_menubars.set(menubar_id, move(menubar));
  101. WSAPI_ServerMessage response;
  102. response.type = WSAPI_ServerMessage::Type::DidCreateMenubar;
  103. response.menu.menubar_id = menubar_id;
  104. post_message(response);
  105. }
  106. void WSClientConnection::handle_request(WSAPIDestroyMenubarRequest& request)
  107. {
  108. int menubar_id = request.menubar_id();
  109. auto it = m_menubars.find(menubar_id);
  110. if (it == m_menubars.end()) {
  111. post_error("Bad menubar ID");
  112. return;
  113. }
  114. auto& menubar = *(*it).value;
  115. WSWindowManager::the().close_menubar(menubar);
  116. m_menubars.remove(it);
  117. WSAPI_ServerMessage response;
  118. response.type = WSAPI_ServerMessage::Type::DidDestroyMenubar;
  119. response.menu.menubar_id = menubar_id;
  120. post_message(response);
  121. }
  122. void WSClientConnection::handle_request(WSAPICreateMenuRequest& request)
  123. {
  124. int menu_id = m_next_menu_id++;
  125. auto menu = make<WSMenu>(this, menu_id, request.text());
  126. m_menus.set(menu_id, move(menu));
  127. WSAPI_ServerMessage response;
  128. response.type = WSAPI_ServerMessage::Type::DidCreateMenu;
  129. response.menu.menu_id = menu_id;
  130. post_message(response);
  131. }
  132. void WSClientConnection::handle_request(WSAPIDestroyMenuRequest& request)
  133. {
  134. int menu_id = static_cast<WSAPIDestroyMenuRequest&>(request).menu_id();
  135. auto it = m_menus.find(menu_id);
  136. if (it == m_menus.end()) {
  137. post_error("Bad menu ID");
  138. return;
  139. }
  140. auto& menu = *(*it).value;
  141. WSWindowManager::the().close_menu(menu);
  142. m_menus.remove(it);
  143. WSAPI_ServerMessage response;
  144. response.type = WSAPI_ServerMessage::Type::DidDestroyMenu;
  145. response.menu.menu_id = menu_id;
  146. post_message(response);
  147. }
  148. void WSClientConnection::handle_request(WSAPISetApplicationMenubarRequest& request)
  149. {
  150. int menubar_id = request.menubar_id();
  151. auto it = m_menubars.find(menubar_id);
  152. if (it == m_menubars.end()) {
  153. post_error("Bad menubar ID");
  154. return;
  155. }
  156. auto& menubar = *(*it).value;
  157. m_app_menubar = menubar.make_weak_ptr();
  158. WSWindowManager::the().notify_client_changed_app_menubar(*this);
  159. WSAPI_ServerMessage response;
  160. response.type = WSAPI_ServerMessage::Type::DidSetApplicationMenubar;
  161. response.menu.menubar_id = menubar_id;
  162. post_message(response);
  163. }
  164. void WSClientConnection::handle_request(WSAPIAddMenuToMenubarRequest& request)
  165. {
  166. int menubar_id = request.menubar_id();
  167. int menu_id = request.menu_id();
  168. auto it = m_menubars.find(menubar_id);
  169. auto jt = m_menus.find(menu_id);
  170. if (it == m_menubars.end()) {
  171. post_error("Bad menubar ID");
  172. return;
  173. }
  174. if (jt == m_menus.end()) {
  175. post_error("Bad menu ID");
  176. return;
  177. }
  178. auto& menubar = *(*it).value;
  179. auto& menu = *(*jt).value;
  180. menubar.add_menu(&menu);
  181. WSAPI_ServerMessage response;
  182. response.type = WSAPI_ServerMessage::Type::DidAddMenuToMenubar;
  183. response.menu.menubar_id = menubar_id;
  184. response.menu.menu_id = menu_id;
  185. post_message(response);
  186. }
  187. void WSClientConnection::handle_request(WSAPIAddMenuItemRequest& request)
  188. {
  189. int menu_id = request.menu_id();
  190. unsigned identifier = request.identifier();
  191. auto it = m_menus.find(menu_id);
  192. if (it == m_menus.end()) {
  193. post_error("Bad menu ID");
  194. return;
  195. }
  196. auto& menu = *(*it).value;
  197. menu.add_item(make<WSMenuItem>(identifier, request.text(), request.shortcut_text()));
  198. WSAPI_ServerMessage response;
  199. response.type = WSAPI_ServerMessage::Type::DidAddMenuItem;
  200. response.menu.menu_id = menu_id;
  201. response.menu.identifier = identifier;
  202. post_message(response);
  203. }
  204. void WSClientConnection::handle_request(WSAPIAddMenuSeparatorRequest& request)
  205. {
  206. int menu_id = request.menu_id();
  207. auto it = m_menus.find(menu_id);
  208. if (it == m_menus.end()) {
  209. post_error("Bad menu ID");
  210. return;
  211. }
  212. auto& menu = *(*it).value;
  213. menu.add_item(make<WSMenuItem>(WSMenuItem::Separator));
  214. WSAPI_ServerMessage response;
  215. response.type = WSAPI_ServerMessage::Type::DidAddMenuSeparator;
  216. response.menu.menu_id = menu_id;
  217. post_message(response);
  218. }
  219. void WSClientConnection::handle_request(WSAPISetWindowOpacityRequest& request)
  220. {
  221. int window_id = request.window_id();
  222. auto it = m_windows.find(window_id);
  223. if (it == m_windows.end()) {
  224. post_error("Bad window ID");
  225. return;
  226. }
  227. auto& window = *(*it).value;
  228. window.set_opacity(request.opacity());
  229. }
  230. void WSClientConnection::handle_request(WSAPISetWindowTitleRequest& request)
  231. {
  232. int window_id = request.window_id();
  233. auto it = m_windows.find(window_id);
  234. if (it == m_windows.end()) {
  235. post_error("Bad window ID");
  236. return;
  237. }
  238. auto& window = *(*it).value;
  239. window.set_title(request.title());
  240. }
  241. void WSClientConnection::handle_request(WSAPIGetWindowTitleRequest& request)
  242. {
  243. int window_id = request.window_id();
  244. auto it = m_windows.find(window_id);
  245. if (it == m_windows.end()) {
  246. post_error("Bad window ID");
  247. return;
  248. }
  249. auto& window = *(*it).value;
  250. WSAPI_ServerMessage response;
  251. response.type = WSAPI_ServerMessage::Type::DidGetWindowTitle;
  252. response.window_id = window.window_id();
  253. ASSERT(window.title().length() < (ssize_t)sizeof(response.text));
  254. strcpy(response.text, window.title().characters());
  255. response.text_length = window.title().length();
  256. post_message(response);
  257. }
  258. void WSClientConnection::handle_request(WSAPISetWindowRectRequest& request)
  259. {
  260. int window_id = request.window_id();
  261. auto it = m_windows.find(window_id);
  262. if (it == m_windows.end()) {
  263. post_error("Bad window ID");
  264. return;
  265. }
  266. auto& window = *(*it).value;
  267. window.set_rect(request.rect());
  268. }
  269. void WSClientConnection::handle_request(WSAPIGetWindowRectRequest& request)
  270. {
  271. int window_id = request.window_id();
  272. auto it = m_windows.find(window_id);
  273. if (it == m_windows.end()) {
  274. post_error("Bad window ID");
  275. return;
  276. }
  277. auto& window = *(*it).value;
  278. WSAPI_ServerMessage response;
  279. response.type = WSAPI_ServerMessage::Type::DidGetWindowRect;
  280. response.window_id = window.window_id();
  281. response.window.rect = window.rect();
  282. post_message(response);
  283. }
  284. void WSClientConnection::handle_request(WSAPISetClipboardContentsRequest& request)
  285. {
  286. auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(request.shared_buffer_id());
  287. if (!shared_buffer) {
  288. post_error("Bad shared buffer ID");
  289. return;
  290. }
  291. WSClipboard::the().set_data(*shared_buffer, request.size());
  292. WSAPI_ServerMessage response;
  293. response.type = WSAPI_ServerMessage::Type::DidSetClipboardContents;
  294. response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id();
  295. post_message(response);
  296. }
  297. void WSClientConnection::handle_request(WSAPIGetClipboardContentsRequest&)
  298. {
  299. WSAPI_ServerMessage response;
  300. response.type = WSAPI_ServerMessage::Type::DidGetClipboardContents;
  301. response.clipboard.shared_buffer_id = -1;
  302. response.clipboard.contents_size = 0;
  303. if (WSClipboard::the().size()) {
  304. // FIXME: Optimize case where an app is copy/pasting within itself.
  305. // We can just reuse the SharedBuffer then, since it will have the same peer PID.
  306. // It would be even nicer if a SharedBuffer could have an arbitrary number of clients..
  307. RetainPtr<SharedBuffer> shared_buffer = SharedBuffer::create(m_pid, WSClipboard::the().size());
  308. ASSERT(shared_buffer);
  309. memcpy(shared_buffer->data(), WSClipboard::the().data(), WSClipboard::the().size());
  310. shared_buffer->seal();
  311. response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id();
  312. response.clipboard.contents_size = WSClipboard::the().size();
  313. // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them.
  314. // After we respond to GetClipboardContents, we have to wait for the client to retain the buffer on his side.
  315. m_last_sent_clipboard_content = move(shared_buffer);
  316. }
  317. post_message(response);
  318. }
  319. void WSClientConnection::handle_request(WSAPICreateWindowRequest& request)
  320. {
  321. int window_id = m_next_window_id++;
  322. auto window = make<WSWindow>(*this, window_id, request.is_modal());
  323. window->set_has_alpha_channel(request.has_alpha_channel());
  324. window->set_resizable(request.is_resizable());
  325. window->set_title(request.title());
  326. window->set_rect(request.rect());
  327. window->set_opacity(request.opacity());
  328. window->set_size_increment(request.size_increment());
  329. window->set_base_size(request.base_size());
  330. window->invalidate();
  331. m_windows.set(window_id, move(window));
  332. WSAPI_ServerMessage response;
  333. response.type = WSAPI_ServerMessage::Type::DidCreateWindow;
  334. response.window_id = window_id;
  335. post_message(response);
  336. }
  337. void WSClientConnection::handle_request(WSAPIDestroyWindowRequest& request)
  338. {
  339. int window_id = request.window_id();
  340. auto it = m_windows.find(window_id);
  341. if (it == m_windows.end()) {
  342. post_error("Bad window ID");
  343. return;
  344. }
  345. auto& window = *(*it).value;
  346. WSWindowManager::the().invalidate(window);
  347. m_windows.remove(it);
  348. }
  349. void WSClientConnection::handle_request(WSAPIInvalidateRectRequest& request)
  350. {
  351. int window_id = request.window_id();
  352. auto it = m_windows.find(window_id);
  353. if (it == m_windows.end()) {
  354. post_error("Bad window ID");
  355. return;
  356. }
  357. auto& window = *(*it).value;
  358. WSAPI_ServerMessage response;
  359. response.type = WSAPI_ServerMessage::Type::Paint;
  360. response.window_id = window_id;
  361. response.paint.rect = request.rect();
  362. response.paint.window_size = window.size();
  363. post_message(response);
  364. }
  365. void WSClientConnection::handle_request(WSAPIDidFinishPaintingNotification& request)
  366. {
  367. int window_id = request.window_id();
  368. auto it = m_windows.find(window_id);
  369. if (it == m_windows.end()) {
  370. post_error("Bad window ID");
  371. return;
  372. }
  373. auto& window = *(*it).value;
  374. if (!window.has_painted_since_last_resize()) {
  375. if (window.last_lazy_resize_rect().size() == request.rect().size()) {
  376. window.set_has_painted_since_last_resize(true);
  377. WSMessageLoop::the().post_message(window, make<WSResizeEvent>(window.last_lazy_resize_rect(), window.rect()));
  378. }
  379. }
  380. WSWindowManager::the().invalidate(window, request.rect());
  381. }
  382. void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& request)
  383. {
  384. int window_id = request.window_id();
  385. auto it = m_windows.find(window_id);
  386. if (it == m_windows.end()) {
  387. post_error("Bad window ID");
  388. return;
  389. }
  390. auto& window = *(*it).value;
  391. auto* backing_store = window.backing_store();
  392. WSAPI_ServerMessage response;
  393. response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore;
  394. response.window_id = window_id;
  395. response.backing.bpp = sizeof(RGBA32);
  396. response.backing.pitch = backing_store->pitch();
  397. response.backing.size = backing_store->size();
  398. response.backing.has_alpha_channel = backing_store->has_alpha_channel();
  399. response.backing.shared_buffer_id = backing_store->shared_buffer_id();
  400. post_message(response);
  401. }
  402. void WSClientConnection::handle_request(WSAPISetWindowBackingStoreRequest& request)
  403. {
  404. int window_id = request.window_id();
  405. auto it = m_windows.find(window_id);
  406. if (it == m_windows.end()) {
  407. post_error("Bad window ID");
  408. return;
  409. }
  410. auto& window = *(*it).value;
  411. if (window.last_backing_store() && window.last_backing_store()->shared_buffer_id() == request.shared_buffer_id()) {
  412. window.swap_backing_stores();
  413. } else {
  414. auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(request.shared_buffer_id());
  415. if (!shared_buffer)
  416. return;
  417. auto backing_store = GraphicsBitmap::create_with_shared_buffer(
  418. request.has_alpha_channel() ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32,
  419. *shared_buffer,
  420. request.size());
  421. window.set_backing_store(move(backing_store));
  422. }
  423. if (request.flush_immediately())
  424. window.invalidate();
  425. WSAPI_ServerMessage response;
  426. response.type = WSAPI_ServerMessage::Type::DidSetWindowBackingStore;
  427. response.window_id = window_id;
  428. response.backing.shared_buffer_id = request.shared_buffer_id();
  429. post_message(response);
  430. }
  431. void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request)
  432. {
  433. int window_id = request.window_id();
  434. auto it = m_windows.find(window_id);
  435. if (it == m_windows.end()) {
  436. post_error("Bad window ID");
  437. return;
  438. }
  439. auto& window = *(*it).value;
  440. window.set_global_cursor_tracking_enabled(request.value());
  441. }
  442. void WSClientConnection::on_request(WSAPIClientRequest& request)
  443. {
  444. switch (request.type()) {
  445. case WSMessage::APICreateMenubarRequest:
  446. return handle_request(static_cast<WSAPICreateMenubarRequest&>(request));
  447. case WSMessage::APIDestroyMenubarRequest:
  448. return handle_request(static_cast<WSAPIDestroyMenubarRequest&>(request));
  449. case WSMessage::APICreateMenuRequest:
  450. return handle_request(static_cast<WSAPICreateMenuRequest&>(request));
  451. case WSMessage::APIDestroyMenuRequest:
  452. return handle_request(static_cast<WSAPIDestroyMenuRequest&>(request));
  453. case WSMessage::APISetApplicationMenubarRequest:
  454. return handle_request(static_cast<WSAPISetApplicationMenubarRequest&>(request));
  455. case WSMessage::APIAddMenuToMenubarRequest:
  456. return handle_request(static_cast<WSAPIAddMenuToMenubarRequest&>(request));
  457. case WSMessage::APIAddMenuItemRequest:
  458. return handle_request(static_cast<WSAPIAddMenuItemRequest&>(request));
  459. case WSMessage::APIAddMenuSeparatorRequest:
  460. return handle_request(static_cast<WSAPIAddMenuSeparatorRequest&>(request));
  461. case WSMessage::APISetWindowTitleRequest:
  462. return handle_request(static_cast<WSAPISetWindowTitleRequest&>(request));
  463. case WSMessage::APIGetWindowTitleRequest:
  464. return handle_request(static_cast<WSAPIGetWindowTitleRequest&>(request));
  465. case WSMessage::APISetWindowRectRequest:
  466. return handle_request(static_cast<WSAPISetWindowRectRequest&>(request));
  467. case WSMessage::APIGetWindowRectRequest:
  468. return handle_request(static_cast<WSAPIGetWindowRectRequest&>(request));
  469. case WSMessage::APISetClipboardContentsRequest:
  470. return handle_request(static_cast<WSAPISetClipboardContentsRequest&>(request));
  471. case WSMessage::APIGetClipboardContentsRequest:
  472. return handle_request(static_cast<WSAPIGetClipboardContentsRequest&>(request));
  473. case WSMessage::APICreateWindowRequest:
  474. return handle_request(static_cast<WSAPICreateWindowRequest&>(request));
  475. case WSMessage::APIDestroyWindowRequest:
  476. return handle_request(static_cast<WSAPIDestroyWindowRequest&>(request));
  477. case WSMessage::APIInvalidateRectRequest:
  478. return handle_request(static_cast<WSAPIInvalidateRectRequest&>(request));
  479. case WSMessage::APIDidFinishPaintingNotification:
  480. return handle_request(static_cast<WSAPIDidFinishPaintingNotification&>(request));
  481. case WSMessage::APIGetWindowBackingStoreRequest:
  482. return handle_request(static_cast<WSAPIGetWindowBackingStoreRequest&>(request));
  483. case WSMessage::APISetGlobalCursorTrackingRequest:
  484. return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request));
  485. case WSMessage::APISetWindowOpacityRequest:
  486. return handle_request(static_cast<WSAPISetWindowOpacityRequest&>(request));
  487. case WSMessage::APISetWindowBackingStoreRequest:
  488. return handle_request(static_cast<WSAPISetWindowBackingStoreRequest&>(request));
  489. default:
  490. break;
  491. }
  492. }
  493. bool WSClientConnection::is_showing_modal_window() const
  494. {
  495. for (auto& it : m_windows) {
  496. auto& window = *it.value;
  497. if (window.is_visible() && window.is_modal())
  498. return true;
  499. }
  500. return false;
  501. }