BsUnixPlatform.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include <Image/BsPixelData.h>
  4. #include <Image/BsPixelUtil.h>
  5. #include <X11/Xutil.h>
  6. #include <X11/Xatom.h>
  7. #include <String/BsUnicode.h>
  8. #include "BsUnixPlatform.h"
  9. #include "BsUnixWindow.h"
  10. namespace bs
  11. {
  12. Event<void(const Vector2I&, const OSPointerButtonStates&)> Platform::onCursorMoved;
  13. Event<void(const Vector2I&, OSMouseButton button, const OSPointerButtonStates&)> Platform::onCursorButtonPressed;
  14. Event<void(const Vector2I&, OSMouseButton button, const OSPointerButtonStates&)> Platform::onCursorButtonReleased;
  15. Event<void(const Vector2I&, const OSPointerButtonStates&)> Platform::onCursorDoubleClick;
  16. Event<void(InputCommandType)> Platform::onInputCommand;
  17. Event<void(float)> Platform::onMouseWheelScrolled;
  18. Event<void(UINT32)> Platform::onCharInput;
  19. Event<void(ct::RenderWindow*)> Platform::onMouseLeftWindow;
  20. Event<void()> Platform::onMouseCaptureChanged
  21. enum class X11CursorType
  22. {
  23. Arrow,
  24. ArrowDrag,
  25. ArrowLeftRight,
  26. Wait,
  27. IBeam,
  28. SizeTopLeft,
  29. SizeTopRight,
  30. SizeBotLeft,
  31. SizeBotRight,
  32. SizeLeft,
  33. SizeRight,
  34. SizeTop,
  35. SizeBottom,
  36. Deny,
  37. Count
  38. };;
  39. struct Platform::Pimpl
  40. {
  41. ::Display* xDisplay = nullptr;
  42. ::Window mainXWindow = 0;
  43. ::Window fullscreenXWindow = 0;
  44. std::unordered_map<::Window, LinuxWindow*> windowMap;
  45. XIM IM;
  46. XIC IC;
  47. Time lastButtonPressTime;
  48. Atom atomDeleteWindow;
  49. // Clipboard
  50. WString clipboardData;
  51. // Cursor
  52. ::Cursor currentCursor = None;
  53. ::Cursor emptyCursor = None;
  54. bool isCursorHidden = false;
  55. Rect2I cursorClipRect;
  56. LinuxWindow* cursorClipWindow = nullptr;
  57. bool cursorClipEnabled = false;
  58. };
  59. static const UINT32 DOUBLE_CLICK_MS = 500;
  60. Platform::Pimpl* Platform::mData = bs_new<Platform::Pimpl>();
  61. Platform::~Platform() { }
  62. Vector2I Platform::getCursorPosition()
  63. {
  64. UINT32 screenCount = XScreenCount(mData->xDisplay);
  65. Vector2I pos;
  66. for(UINT32 i = 0; i < screenCount; ++i)
  67. {
  68. ::Window outRoot, outChild;
  69. INT32 childX, childY;
  70. UINT32 mask;
  71. XQueryPointer(mData->xDisplay, XRootWindow(mData->xDisplay, i), &outRoot, &outChild, &pos.x,
  72. &pos.y, &childX, &childY, &mask);
  73. }
  74. return pos;
  75. }
  76. void Platform::setCursorPosition(const Vector2I& screenPos)
  77. {
  78. UINT32 screenCount = XScreenCount(mData->xDisplay);
  79. // Note assuming screens are laid out horizontally left to right
  80. INT32 screenX = 0;
  81. for(UINT32 i = 0; i < screenCount; ++i)
  82. {
  83. ::Window root = XRootWindow(mData->xDisplay, i);
  84. INT32 screenXEnd = screenX + XDisplayWidth(mData->xDisplay, i);
  85. if(screenPos.x >= screenX && screenPos.x < screenXEnd)
  86. {
  87. XWarpPointer(mData->xDisplay, None, root, 0, 0, 0, 0, screenPos.x, screenPos.y);
  88. XFlush(mData->xDisplay);
  89. return;
  90. }
  91. screenX = screenXEnd;
  92. }
  93. }
  94. void Platform::captureMouse(const RenderWindow& window)
  95. {
  96. // TODOPORT
  97. }
  98. void Platform::releaseMouseCapture()
  99. {
  100. // TODOPORT
  101. }
  102. bool Platform::isPointOverWindow(const RenderWindow& window, const Vector2I& screenPos)
  103. {
  104. // TODOPORT
  105. return false;
  106. }
  107. void applyCurrentCursor(Platform::Pimpl* data, ::Window window)
  108. {
  109. if(data->isCursorHidden)
  110. XDefineCursor(data->xDisplay, window, data->emptyCursor);
  111. else
  112. {
  113. if (data->currentCursor != None)
  114. XDefineCursor(data->xDisplay, window, data->currentCursor);
  115. else
  116. XUndefineCursor(data->xDisplay, window);
  117. }
  118. }
  119. void updateClipBounds(Platform::Pimpl* data, LinuxWindow* window)
  120. {
  121. if(!data->cursorClipEnabled || data->cursorClipWindow != window)
  122. return;
  123. data->cursorClipRect.x = window->getLeft();
  124. data->cursorClipRect.y = window->getTop();
  125. data->cursorClipRect.width = window->getWidth();
  126. data->cursorClipRect.height = window->getHeight();
  127. }
  128. bool clipCursor(Platform::Pimpl* data, Vector2I& pos)
  129. {
  130. if(!data->cursorClipEnabled)
  131. return false;
  132. int32_t clippedX = pos.x - data->cursorClipRect.x;
  133. int32_t clippedY = pos.y - data->cursorClipRect.y;
  134. if(clippedX < 0)
  135. clippedX = data->cursorClipRect.x + data->cursorClipRect.width + clippedX;
  136. else if(clippedX >= data->cursorClipRect.width)
  137. clippedX = data->cursorClipRect.x + (clippedX - data->cursorClipRect.width);
  138. else
  139. clippedX = data->cursorClipRect.x + clippedX;
  140. if(clippedY < 0)
  141. clippedY = data->cursorClipRect.y + data->cursorClipRect.height + clippedY;
  142. else if(clippedY >= data->cursorClipRect.height)
  143. clippedY = data->cursorClipRect.y + (clippedY - data->cursorClipRect.height);
  144. else
  145. clippedY = data->cursorClipRect.y + clippedY;
  146. if(clippedX != pos.x || clippedY != pos.y)
  147. {
  148. pos.x = clippedX;
  149. pos.y = clippedY;
  150. return true;
  151. }
  152. return false;
  153. }
  154. void Platform::hideCursor()
  155. {
  156. mData->isCursorHidden = true;
  157. for(auto& entry : mData->windowMap)
  158. applyCurrentCursor(mData, entry.first);
  159. }
  160. void Platform::showCursor()
  161. {
  162. mData->isCursorHidden = false;
  163. for(auto& entry : mData->windowMap)
  164. applyCurrentCursor(mData, entry.first);
  165. }
  166. bool Platform::isCursorHidden()
  167. {
  168. return mData->isCursorHidden;
  169. }
  170. void Platform::clipCursorToWindow(const RenderWindow& window)
  171. {
  172. mData->cursorClipEnabled = true;
  173. mData->cursorClipWindow = window->_getInternal();
  174. updateClipBounds(window);
  175. Vector2I pos = getCursorPosition();
  176. if(clipCursor(mData, pos))
  177. setCursorPosition(pos);
  178. }
  179. void Platform::clipCursorToRect(const Rect2I& screenRect)
  180. {
  181. mData->cursorClipEnabled = true;
  182. mData->cursorClipRect = screenRect;
  183. mData->cursorClipWindow = nullptr;
  184. Vector2I pos = getCursorPosition();
  185. if(clipCursor(mData, pos))
  186. setCursorPosition(pos);
  187. }
  188. void Platform::clipCursorDisable()
  189. {
  190. mData->cursorClipEnabled = false;
  191. mData->cursorClipWindow = None;
  192. }
  193. void Platform::setCursor(PixelData& pixelData, const Vector2I& hotSpot)
  194. {
  195. // TODOPORT
  196. }
  197. void Platform::setIcon(const PixelData& pixelData)
  198. {
  199. SPtr<PixelData> resizedData = PixelData::create(32, 32, 1, PF_RGBA8);
  200. PixelUtil::scale(pixelData, *resizedData);
  201. // TODOPORT
  202. }
  203. void Platform::setCaptionNonClientAreas(const ct::RenderWindow& window, const Vector<Rect2I>& nonClientAreas)
  204. {
  205. // TODOPORT
  206. }
  207. void Platform::setResizeNonClientAreas(const ct::RenderWindow& window, const Vector<NonClientResizeArea>& nonClientAreas)
  208. {
  209. // Do nothing, resize areas not supported on Linux (but they are provided even on undecorated windows by the WM)
  210. }
  211. void Platform::resetNonClientAreas(const ct::RenderWindow& window)
  212. {
  213. // Do nothing, resize areas not supported on Linux (but they are provided even on undecorated windows by the WM)
  214. }
  215. void Platform::sleep(UINT32 duration)
  216. {
  217. usleep(duration * 1000);
  218. }
  219. OSDropTarget& Platform::createDropTarget(const RenderWindow* window, int x, int y, unsigned int width, unsigned int height)
  220. {
  221. // TODOPORT
  222. }
  223. void Platform::destroyDropTarget(OSDropTarget& target)
  224. {
  225. // TODOPORT
  226. }
  227. void Platform::copyToClipboard(const WString& string)
  228. {
  229. mData->clipboardData = string;
  230. Atom clipboardAtom = XInternAtom(mData->xDisplay, "CLIPBOARD", 0);
  231. XSetSelectionOwner(mData->xDisplay, clipboardAtom, mData->mainXWindow, CurrentTime);
  232. }
  233. WString Platform::copyFromClipboard()
  234. {
  235. Atom clipboardAtom = XInternAtom(mData->xDisplay, "CLIPBOARD", 0);
  236. ::Window selOwner = XGetSelectionOwner(mData->xDisplay, clipboardAtom);
  237. if(selOwner == None)
  238. return L"";
  239. if(selOwner == mData->mainXWindow)
  240. return mData->clipboardData;
  241. XConvertSelection(mData->xDisplay, clipboardAtom, XA_STRING, clipboardAtom, mData->mainXWindow,
  242. CurrentTime);
  243. XFlush(mData->xDisplay);
  244. // Note: This might discard events if there are any in between the one we need. Ideally we let the
  245. // processEvents() handle them
  246. while(true)
  247. {
  248. XEvent event;
  249. XNextEvent(mData->xDisplay, &event);
  250. if(event.type == SelectionNotify && event.xselection.requestor == mData->mainXWindow)
  251. break;
  252. }
  253. Atom actualType;
  254. INT32 actualFormat;
  255. unsigned long length;
  256. unsigned long bytesRemaining;
  257. UINT8* data;
  258. XGetWindowProperty(mData->xDisplay, mData->mainXWindow, clipboardAtom,
  259. 0, 0, False, AnyPropertyType, &actualType, &actualFormat, &length, &bytesRemaining, &data);
  260. if(bytesRemaining > 0)
  261. {
  262. unsigned long unused;
  263. INT32 result = XGetWindowProperty(mData->xDisplay, mData->mainXWindow, clipboardAtom,
  264. 0, bytesRemaining, False, AnyPropertyType, &actualType, &actualFormat, &length,
  265. &unused, &data);
  266. if(result == Success)
  267. return UTF8::toWide(String((const char*)data));
  268. XFree(data);
  269. }
  270. return L"";
  271. }
  272. WString Platform::keyCodeToUnicode(UINT32 keyCode)
  273. {
  274. // TODOPORT
  275. return L"";
  276. }
  277. void Platform::_messagePump()
  278. {
  279. while(XPending(mData->xDisplay) > 0)
  280. {
  281. XEvent event;
  282. XNextEvent(mData->xDisplay, &event);
  283. switch (event.type)
  284. {
  285. case ClientMessage:
  286. {
  287. if(event.xclient.data.l[0] == mData->atomDeleteWindow)
  288. XDestroyWindow(mData->xDisplay, event.xclient.window);
  289. }
  290. break;
  291. case DestroyNotify:
  292. {
  293. auto iterFind = mData->windowMap.find(event.xdestroywindow.window);
  294. if (iterFind == mData->windowMap.end())
  295. break;
  296. LinuxWindow* window = iterFind->second;
  297. window->_cleanUp();
  298. if(mData->mainXWindow == 0)
  299. return;
  300. }
  301. break;
  302. case KeyPress:
  303. {
  304. // Process text input
  305. //// Check if input manager wants this event. If not, we process it.
  306. if(!XFilterEvent(&event, None))
  307. {
  308. Status status;
  309. uint8_t buffer[16];
  310. int32_t length = Xutf8LookupString(mData->IC, &event.xkey, (char*)buffer, sizeof(buffer), nullptr,
  311. &status);
  312. if(length > 0)
  313. {
  314. buffer[length] = '\0';
  315. // TODOPORT - Buffer now contains the UTF8 value of length 'length' bytes. I can consider converting
  316. // it to single UTF32 before returning
  317. }
  318. }
  319. // Process normal key press
  320. {
  321. static XComposeStatus keyboard;
  322. uint8_t buffer[16];
  323. KeySym symbol;
  324. XLookupString(&event.xkey, (char*)buffer, sizeof(buffer), &symbol, &keyboard);
  325. bool alt = event.xkey.state & Mod1Mask;
  326. bool control = event.xkey.state & ControlMask;
  327. bool shift = event.xkey.state & ShiftMask;
  328. // TODOPORT - Report key press
  329. }
  330. }
  331. break;
  332. case KeyRelease:
  333. {
  334. uint8_t buffer[16];
  335. KeySym symbol;
  336. XLookupString(&event.xkey, (char *) buffer, sizeof(buffer), &symbol, nullptr);
  337. bool alt = (event.xkey.state & Mod1Mask) != 0;
  338. bool control = (event.xkey.state & ControlMask) != 0;
  339. bool shift = (event.xkey.state & ShiftMask) != 0;
  340. // TODOPORT - Report key release
  341. }
  342. break;
  343. case ButtonPress:
  344. {
  345. uint32_t button = event.xbutton.button;
  346. switch(button)
  347. {
  348. // Button 4 & 5 is vertical wheel, 6 & 7 horizontal wheel, and we handle them elsewhere
  349. case Button1: // Left
  350. case Button2: // Middle
  351. case Button3: // Right
  352. case 8:
  353. case 9:
  354. int32_t x = event.xbutton.x_root;
  355. int32_t y = event.xbutton.y_root;
  356. bool alt = (event.xbutton.state & Mod1Mask) != 0;
  357. bool control = (event.xbutton.state & ControlMask) != 0;
  358. bool shift = (event.xbutton.state & ShiftMask) != 0;
  359. // TODOPORT - Report button press
  360. break;
  361. }
  362. // Handle double-click
  363. if(event.xbutton.time < (mData->lastButtonPressTime + DOUBLE_CLICK_MS))
  364. {
  365. // TODOPORT - Trigger double-click
  366. mData->lastButtonPressTime = 0;
  367. }
  368. else
  369. mData->lastButtonPressTime = event.xbutton.time;
  370. // Handle window dragging for windows without a title bar
  371. if(button == Button1)
  372. {
  373. auto iterFind = mData->windowMap.find(event.xbutton.window);
  374. if (iterFind != mData->windowMap.end())
  375. {
  376. LinuxWindow* window = iterFind->second;
  377. window->_dragStart(event.xbutton.x, event.xbutton.y);
  378. }
  379. }
  380. break;
  381. }
  382. case ButtonRelease:
  383. {
  384. uint32_t button = event.xbutton.button;
  385. bool alt = (event.xbutton.state & Mod1Mask) != 0;
  386. bool control = (event.xbutton.state & ControlMask) != 0;
  387. bool shift = (event.xbutton.state & ShiftMask) != 0;
  388. switch(button)
  389. {
  390. case Button2: // Middle
  391. case Button3: // Right
  392. case 8:
  393. case 9:
  394. {
  395. int32_t x = event.xbutton.x_root;
  396. int32_t y = event.xbutton.y_root;
  397. // TODOPORT - Report button release
  398. break;
  399. }
  400. case Button4: // Vertical mouse wheel
  401. case Button5:
  402. {
  403. int32_t delta = button == Button4 ? 1 : -1;
  404. // TODOPORT - Send mouse wheel scroll
  405. }
  406. break;
  407. case 6: // Horizontal mouse wheel
  408. case 7:
  409. {
  410. int32_t delta = button == 6 ? 1 : -1;
  411. // TODOPORT - Send mouse wheel scroll
  412. }
  413. break;
  414. }
  415. // Handle window dragging for windows without a title bar
  416. if(button == Button1)
  417. {
  418. auto iterFind = mData->windowMap.find(event.xbutton.window);
  419. if (iterFind != mData->windowMap.end())
  420. {
  421. LinuxWindow* window = iterFind->second;
  422. window->_dragEnd();
  423. }
  424. }
  425. break;
  426. }
  427. case MotionNotify:
  428. {
  429. Vector2I pos;
  430. pos.x = event.xmotion.x_root;
  431. pos.y = event.xmotion.y_root;
  432. // Handle clipping if enabled
  433. if(clipCursor(mData, pos))
  434. setCursorPosition(pos);
  435. // TODOPORT - Send mouse move event
  436. // Handle window dragging for windows without a title bar
  437. auto iterFind = mData->windowMap.find(event.xmotion.window);
  438. if (iterFind != mData->windowMap.end())
  439. {
  440. LinuxWindow* window = iterFind->second;
  441. window->_dragUpdate(event.xmotion.x, event.xmotion.y);
  442. }
  443. }
  444. break;
  445. case EnterNotify:
  446. if(event.xcrossing.mode == NotifyNormal)
  447. {
  448. // TODOPORT - Send mouse enter event
  449. }
  450. break;
  451. case LeaveNotify:
  452. if(event.xcrossing.mode == NotifyNormal)
  453. {
  454. Vector2I pos;
  455. pos.x = event.xcrossing.x_root;
  456. pos.y = event.xcrossing.y_root;
  457. if(clipCursor(mData, pos))
  458. setCursorPosition(pos);
  459. // TODOPORT - Send mouse leave event
  460. }
  461. break;
  462. case ConfigureNotify:
  463. {
  464. const XConfigureEvent &xce = event.xconfigure;
  465. auto iterFind = mData->windowMap.find(event.xdestroywindow.window);
  466. if (iterFind == mData->windowMap.end())
  467. break;
  468. LinuxWindow* window = iterFind->second;
  469. updateClipBounds(mData, window);
  470. // TODOPORT - Send move/resize event
  471. }
  472. break;
  473. case FocusIn:
  474. // Update input context focus
  475. XSetICFocus(mData->IC);
  476. break;
  477. case FocusOut:
  478. // Update input context focus
  479. XUnsetICFocus(mData->IC);
  480. break;
  481. case SelectionRequest:
  482. {
  483. // Send the data saved by the last clipboard copy operation
  484. Atom compoundTextAtom = XInternAtom(mData->xDisplay, "COMPOUND_TEXT", 0);
  485. Atom utf8StringAtom = XInternAtom(mData->xDisplay, "UTF8_STRING", 0);
  486. Atom targetsAtom = XInternAtom(mData->xDisplay, "TARGETS", 0);
  487. XSelectionRequestEvent& selReq = event.xselectionrequest;
  488. XEvent response;
  489. if(selReq.target == XA_STRING || selReq.target == compoundTextAtom || selReq.target == utf8StringAtom)
  490. {
  491. String utf8data = UTF8::fromWide(mData->clipboardData);
  492. const uint8_t* data = (const uint8_t*)utf8data.c_str();
  493. int32_t dataLength = utf8data.length();
  494. XChangeProperty(mData->xDisplay, selReq.requestor, selReq.property,
  495. selReq.target, 8, PropModeReplace, data, dataLength);
  496. response.xselection.property = selReq.property;
  497. }
  498. else if(selReq.target == targetsAtom)
  499. {
  500. Atom data[2];
  501. data[0] = utf8StringAtom;
  502. data[1] = XA_STRING;
  503. XChangeProperty (mData->xDisplay, selReq.requestor, selReq.property, selReq.target,
  504. 8, PropModeReplace, (unsigned char*)&data, sizeof (data));
  505. response.xselection.property = selReq.property;
  506. }
  507. else
  508. {
  509. response.xselection.property = None;
  510. }
  511. response.xselection.type = SelectionNotify;
  512. response.xselection.display = selReq.display;
  513. response.xselection.requestor = selReq.requestor;
  514. response.xselection.selection = selReq.selection;
  515. response.xselection.target = selReq.target;
  516. response.xselection.time = selReq.time;
  517. XSendEvent (mData->xDisplay, selReq.requestor, 0, 0, &response);
  518. XFlush (mData->xDisplay);
  519. }
  520. break;
  521. default:
  522. break;
  523. }
  524. }
  525. }
  526. void Platform::_startUp()
  527. {
  528. // XInitThreads(); // TODO: Not sure if this will be necessary
  529. mData->xDisplay = XOpenDisplay(nullptr);
  530. if(XSupportsLocale())
  531. {
  532. XSetLocaleModifiers("");
  533. mData->IM = XOpenIM(mData->xDisplay, nullptr, nullptr, nullptr);
  534. // Note: Currently our windows don't support pre-edit and status areas, which are used for more complex types
  535. // of character input. Later on it might be beneficial to support them.
  536. mData->IC = XCreateIC(mData->IM, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, nullptr);
  537. }
  538. mData->atomDeleteWindow = XInternAtom(mData->xDisplay, "WM_DELETE_WINDOW", False);
  539. // Create empty cursor
  540. char data[1];
  541. memset(data, 0, sizeof(data));
  542. Pixmap pixmap = XCreateBitmapFromData(mData->xDisplay, DefaultRootWindow(mData->xDisplay), data, 1, 1);
  543. XColor color;
  544. color.red = color.green = color.blue = 0;
  545. mData->emptyCursor = XCreatePixmapCursor(mData->xDisplay, pixmap, pixmap, &color, &color, 0, 0);
  546. XFreePixmap(mData->xDisplay, pixmap);
  547. }
  548. void Platform::_update()
  549. {
  550. // Do nothing
  551. }
  552. void Platform::_coreUpdate()
  553. {
  554. _messagePump();
  555. }
  556. void Platform::_shutDown()
  557. {
  558. // Free empty cursor
  559. XFreeCursor(mData->xDisplay, mData->emptyCursor);
  560. mData->emptyCursor = None;
  561. if(mData->IC)
  562. {
  563. XDestroyIC(mData->IC);
  564. mData->IC = 0;
  565. }
  566. if(mData->IM)
  567. {
  568. XCloseIM(mData->IM);
  569. mData->IM = 0;
  570. }
  571. XCloseDisplay(mData->xDisplay);
  572. mData->xDisplay = nullptr;
  573. bs_delete(mData);
  574. mData = nullptr;
  575. }
  576. ::Display* LinuxPlatform::getXDisplay()
  577. {
  578. return mData->xDisplay;
  579. }
  580. ::Window LinuxPlatform::getMainXWindow()
  581. {
  582. return mData->mainXWindow;
  583. }
  584. void LinuxPlatform::_registerWindow(::Window xWindow, LinuxWindow* window)
  585. {
  586. // First window is assumed to be the main
  587. if(mData->mainXWindow == 0)
  588. {
  589. mData->mainXWindow = xWindow;
  590. // Input context client window must be set before use
  591. XSetICValues(mData->IC,
  592. XNClientWindow, xWindow,
  593. XNFocusWindow, xWindow,
  594. nullptr);
  595. }
  596. mData->windowMap[xWindow] = window;
  597. applyCurrentCursor(mData, xWindow);
  598. }
  599. void LinuxPlatform::_unregisterWindow(::Window xWindow)
  600. {
  601. auto iterFind = mData->windowMap.find(xWindow);
  602. if(iterFind != mData->windowMap.end())
  603. {
  604. if(mData->cursorClipEnabled && mData->cursorClipWindow == iterFind->second)
  605. clipCursorDisable();
  606. mData->windowMap.erase(iterFind);
  607. }
  608. if(mData->mainXWindow == xWindow)
  609. mData->mainXWindow = 0;
  610. }
  611. Pixmap LinuxPlatform::createPixmap(const SPtr<PixelData>& data)
  612. {
  613. SPtr<PixelData> bgraData = PixelData::create(data->getWidth(), data->getHeight(), 1, PF_BGRA8);
  614. PixelUtil::bulkPixelConversion(*data, *bgraData);
  615. uint32_t depth = XDefaultDepth(mData->xDisplay, 0);
  616. XImage* image = XCreateImage(mData->xDisplay, XDefaultVisual(mData->xDisplay, 0), depth, ZPixmap, 0,
  617. (char*)bgraData->getData(), data->getWidth(), data->getHeight(), 32, 0);
  618. Pixmap pixmap = XCreatePixmap(mData->xDisplay, XDefaultRootWindow(mData->xDisplay),
  619. data->getWidth(), data->getHeight(), depth);
  620. XGCValues gcValues;
  621. GC gc = XCreateGC(mData->xDisplay, pixmap, 0, &gcValues);
  622. XPutImage(mData->xDisplay, pixmap, gc, image, 0, 0, 0, 0, data->getWidth(), data->getHeight());
  623. XFreeGC(mData->xDisplay, gc);
  624. // Make sure XDestroyImage doesn't free the data pointed to by 'data.bytes'
  625. image->data = nullptr;
  626. XDestroyImage(image);
  627. return pixmap;
  628. }
  629. }