WSClientConnection.cpp 20 KB

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