WSClientConnection.cpp 40 KB

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